这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
为什么 Go 语言把类型放在后面?
示例代码:
var a []string
var b []string
其实在早年 Go 官方估计已经被问烦了,写过一篇《Go’s Declaration Syntax》来具体介绍和说明情况。
类型前置
在业内目前有不少知名语言,也采取的是在声明变量类型时,把类型定义在名字前面。像是 C、C++、C#、Java 等:
int x;
int x = 100;
基本的格式定义:<data_type> <variable_list>;。
上面的声明是一个简单的例子,如果更复杂一些,Go 官方还给出了著名的函数指针的例子:
int (*fp)(int a, int b);
更进一步,如果返回值也是个函数指针类型,就会变成:
int (*(*fp)(int (*)(int, int), int))(int, int)
这已经很难看出来是个 fp 的声明了。
类型后置
前面所举例的类型前置的编程语言,很多都是 C 系列中的一者。类型后置的代表,分别有:Go、Rust、Scala、Kotlin 等。
其实在很多类型后置的编程语言种,会采取变量名+冒号+类型的方式出现。就像 Rust 一样:
let x: i32;
基本的格式定义:
x: int
p: pointer to int
a: array[3] of int
Go 官方参照了这类类型后置的设计,并且为了简洁,进一步去掉了冒号和一些关键字,变成:
var a []string
我们再看回前面 fp 的声明的例子:
int (*(*fp)(int (*)(int, int), int))(int, int)
再对比 Go 语言中就变成了:
f func(func(int,int) int, int) func(int, int) int
两者一对比,Go 语言代码可读性确实更高一些。
思考
后置类别
在类型声明上,实际上分为:变量类型后置、函数返回值后置。两者共同构建了前置还是后置,总不能一个前置,一个后置吧,那得多么的难受。
上方 C 语言和 Go 语言函数指针的例子,所对比带来的代码可读性提高,其实本质上是由函数返回值后置所带来的。
和类型前置、后置没太多直接关系。
核心思想
在类型后置上来讲,Go 官方核心思想是:这种声明方式(从左到右的风格)的一个优点是,当类型变得更加复杂时,它的效果非常好(One merit of this left-to-right style is how well it works as the types become more complex)。
Go 的变量名总是在前,在人的代码阅读上可以保持从左到右阅读,不需要像 C 语言一样在一大堆声明中用技巧找变量名对应的类型。
为此甚至有人写了篇 C 语言的顺时针读法《The Clockwise/Spiral Rule》,有兴趣可以阅读。
如此一对比,Go 语言的类型后置在复杂场景下与 C 语言的对比确实更好一些。
其他因素
类型推导
诸如在类型推导的形式上也会更直观:
func main() {
var s1 := "AAA"
var s2 string
}
也是一个可读性提高的问题。