转载

Go语言与众不同的类型定义

Go语言与众不同的类型定义

前几天同事在学习Go语言,对Go的变量类型定义一直吐槽。 觉得和之前的编程习惯太违背,之前的编程习惯也就是C语言的变量定义。 很多人第一次接触Go的时候都喜欢这个槽点。

但是其实个人觉得主要原因在于惯性思维,C语言本身的类型定义才是反人类的。 举一个例子就可以很清楚的说明了,先看以下的C语言定义的全局变量x是什么类型?

#include <stdio.h>  int*(*x[5])[5];  int main() {   int i = 10;   int* ii[5];   ii[0] = &i;   x[0]=ⅈ   printf("%d/n", *(*x[0])[0]);   return 0; } 

答案: x是数组,数组的元素是指针,指针的指向是数组,数组的元素是指针,指针指向的是int

而得知这个答案的过程是由里往外的推理, 先看最里面的x变量, 然后再在脑海里面想一想对于 * 运算符和 [] 运算符哪个优先级更高? 结论是 [] 优先级更高, 然后就推理x是数组,然后数组的元素则是指针,也就是左边的 * 运算符得知的。 然后再把 (*x[5]) 当成一个整体去看, 可以假定先把 int*(*x[5])[5] 先写成 int*(y)[5] 去推理, y是x数组的元素指向的变量, 然后y是数组,数组的元素类型是指针,指针指向的是int类型。

是一种递归的方式从里面往外面推理。

而看看对于同样的变量类型,Go语言是如下的代码:

package main import "fmt" func main() {  // x是数组,数组的元素是指针,指针的指向是数组,数组的元素是指针,指针指向的是int  // y是数组,数组的元素是指针,指针的指向是int  var x [5]*[5]*int  var y [5]*int  x[0] = &y  fmt.Printf("%v/n", y)  fmt.Printf("%v/n", x) }  

在Go里面,对于x变量的类型推理,是从左往右推理即可(更符合人类的直觉,也更容易写语法的Parser)

比如对于 var x[5]*[5]*int 可以推理如下:

x[5] 是数组 x[5]* 是数组,数组的元素是指针。 x[5]*[5] 是数组,数组的元素是指针,指针指向的元素又是数组。 x[5]*[5]* 是数组,数组的元素是指针,指针指向的元素又是数组,数组的元素是指针。 x[5]*[5]*int 是数组,数组的元素是指针,指针指向的元素又是数组,数组的元素是指针,指针指向的元素是int。

是不是想到数学老师喜欢说的一句话:『从左往右,依次演算。』

符合人类的直接,写起Parser来也更简单,不需要递归, 理论上来讲Go的Parser对于类型解析应该是比C语言的类型解析更快的。

而C语言的类型定义则是由内向外的,写Parser也得递归地去解析。 而且对于人类的思维来说也是更复杂的,只不过因为大家是从C语言入门的。 所以没有感觉到这个语法的设计是反人类的。

而Go语言的作者之一 Ken Thompson 就是当年B语言和C语言设计者之一。 所以我觉得Go语言是有意修复C语言在类型定义中反人类的地方。 但是却被已经习惯了C语言语法的人以为Go是在故意刁难开发者。

所以写这篇文章,说这么多, 就是希望学习Go语言的开发者能理解关于类型定义与众不同的原因。

正文到此结束
Loading...