先写名字,再写类型:为什么“age int”比“int age”更好
摘要:变量名比类型更重要,因此在声明中,名字应该更醒目、放在前面。
在 C、C++、Java 和 C# 等许多主流编程语言中,定义字段或变量时都是先写类型、再写名字。例如(以 C++ 为例):
// Struct definition
struct person {
std::string name;
std::string email;
int age;
};
// Stand-alone variables
std::vector<person> people = get_people();
int min_age = find_minimum_age(people);
std::string domain = parse_email_domain(people[0].email);而在 Go、Rust、TypeScript 和 Python(带类型提示)等另一些语言中,则是先写名字、再写类型。例如(以 Go 为例):
// Struct definition
type Person struct {
Name string
Email string
Age int
}
// Stand-alone variables
var people []Person = getPeople()
var minAge int = findMinimumAge(people)
var domain string = parseEmailDomain(people[0].Email)
// Though it's more typical in Go to use := (short variable declarations)
people := getPeople()
minAge := findMinimumAge(people)
domain := parseEmailDomain(people[0].Email)Go FAQ 中有一个关于 Go 为何选择这种顺序的精彩回答:“Why are declarations backwards?”。回答开头就说“只有当你习惯了 C,才会觉得它是反的”,这话很有道理——先写名字的声明方式在 Pascal 这类语言中有着悠久的历史。事实上,Go 的类型声明语法(以及包机制)就直接借鉴了 Pascal。
FAQ 还进一步指出,先写名字的语法让解析更简单,而且在同时声明多个变量时,比 C 语言更不容易出错。在 C 语言中,下面这行会把 x 声明为指针,但(乍一看有点出人意料!)y 却是一个普通的整数:
int* x, y;而 Go 中与之等价的写法则符合直觉,会把两者都声明为指针:
var x, y *intGo 官方博客上还有一篇由 Rob Pike 撰写的深度文章 Go’s Declaration Syntax,更详细地阐述了 Go 的语法相较于 C 的优势,尤其是在数组和函数指针方面。
奇怪的是,这篇文章只是顺带提到了我认为在日常编程中更偏爱先写名字的那个更重要的原因:这样更清晰。
变量名比类型更重要,因此在声明中,名字应该更醒目、放在前面。
我认为这一点很容易从几个不同角度得到证明:
- 从变量声明中类型推断的普及程度就能看出,这项特性如今在大多数语言中都有:C# 和 Java 中的
var、Go 中的:=、C++ 中的auto等等。 - 从动态类型语言(如 Python 和 Ruby)的存在也能看出——它们根本不需要类型,你只有名字!
- 名字承载了更多的语义。在上面的例子中,
minAge显然表示最小年龄这个值,而知道它是int并没有增加多少信息。当然,这对类型检查很有用,但即使类型是推断出来的,代码依然清晰。(英语中也有类型推断:你绝不会说“Person Ben Hoyt 写了这篇文字文章。”)
我持有这个观点已经有一段时间了,但促使我把它写下来的,是最近发布的 Cap’n Proto 1.0,它让我想起了 Protocol Buffers 与 Cap’n Proto 在 schema 语法上的差异。
在下面两个例子中,哪一个更容易一眼看出字段名?这是 Protocol Buffers 的 schema:
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}还是这个 Cap’n Proto 的:
struct SearchResponse {
results @1 :List(Result);
}
struct Result {
url @1 :Text;
title @2 :String;
snippets @3 :List(Text);
}不知道你怎么看,反正我觉得最重要的部分(字段名)在 Protocol Buffers 的版本里有点被淹没了。而在 Cap’n Proto 的版本中,由于左对齐,字段名一目了然。
我想说的要点是:过去无法改变,但如果你正在创造一门新语言,请把名字放在类型前面!
随机一篇博客
评论
登录后参与讨论