8.2. 语法
Go中变量的声明语法和C++相反。定义变量时,先写变量的名字,然后是变量的类型。这样 不会出现像C++中, 类型不能匹配后面所有变量的情况(指针类型)。而且语法清晰,便于 阅读。
Go C++
var v1 int // int v1;
var v2 string // const std::string v2; (approximately 近似等价)
var v3 [10]int // int v3[10];
var v4 []int // int* v4; (approximately 近似等价)
var v5 struct { f int } // struct { int f; } v5;
var v6 *int // int* v6; (but no pointer arithmetic 没有指针算术)
var v7 map[string]int // unordered_map<string, int>* v7; (approximately 近似等价)
var v8 func(a int) int // int (*v8)(int a);
变量的声明通常是从某些关键字开始,例如var, func,const或type。对于类型的专有方法定义, 在变量名前面还要加上对应该方法发类型对象变量,细节清参考discussion of interfaces。
你也可以在关键字后面加括号,这样可以同时定义多个变量。
var (
i int
m float
)
When declaring a function, you must either provide a name for each parameter or not provide a name for any parameter; you can't omit some names and provide others. You may group several names with the same type:
定义函数的时候,你可以指定每个参数的名字或者不指定任何参数名字,但是你不能只指定部分函数参数的 名字。如果是相邻的参数是相同的类型,也可以统一指定类型。
func f(i, j, k int, s, t string)
对于变量,可以在定时进行初始化。对于这种情况,我们可以省略变量的类型部分,因为Go编译器 可以根据初始化的值推导出变量的类型。
var v = *p
如果变量定义时没有初始化,则必须指定类型。没有显式初始化的变量,会被自动初始化为空的值, 例如0,nil等。Go不存在完全未初始化的变量。
用:=操作符,还有更简短的定义语法:
v1 := v2
和下面语句等价:
var v1 = v2
Go还提供多个变量同时赋值:
i, j = j, i // Swap i and j.
函数也可以返回多个值,多个返回值需要用括号括起来。返回值可以用一个等于符号赋给 多个变量。
func f() (i int, j int) { ... }
v1, v2 = f()
Go中使用很少的分号,虽然每个语句之间实际上是用分号分割的。因为,go编译器会在看似 完整的语句末尾自动添加分号(具体细节清参考Go语言手册)。 当然,自动添加分号也可能带来一些问题。例如:
func g()
{ // INVALID
}
在g()函数后面会被自动添加分号,导致函数编译出错。下面的代码也有类似的 问题:
if x {
}
else { // INVALID
}
在第一个花括号}的后面会被自动添加分号,导致else语句 出现语法错误。
分号可以用来分割语句,你仍然可以安装C++的方式来使用分号。不过Go语言中,常常省略不 必要的分号。 只有在 循环语句的初始化部分,或者一行写多个语句的时候才是必须的。
继续前面的问题。我们并不用担心因为花括号的位置导致的编译错误,因此我们可以用 gofmt 来排版程序代码。 gofmt 工具总是可以将代码排版成统一的风格。While the style may initially seem odd, it is as good as any other style, and familiarity will lead to comfort.
当用指针访问结构体的时候,我们用.代替->语法。 因此,用结构体类型和结构体指针类型访问结构体成员的语法是一样的。
type myStruct struct { i int }
var v9 myStruct // v9 has structure type
var p9 *myStruct // p9 is a pointer to a structure
f(v9.i, p9.i)
Go不要求在if语句的条件部分用小括弧,但是要求if后面的代码 部分必须有花括弧。类似的规则也适用于for和switch等语句。
if a < b { f() } // Valid
if (a < b) { f() } // Valid (condition is a parenthesized expression)
if (a < b) f() // INVALID
for i = 0; i < 10; i++ {} // Valid
for (i = 0; i < 10; i++) {} // INVALID
Go语言中没有while和do/while循环语句。我们可以用只有一个 条件语句的for来代替while循环。如果省略for 的条件部分,则是一个无限循环。
Go增加了带标号的break 和continue语法。不过标号必须 是针对for,switch或select代码段的。
对于switch语句,case匹配后不会再继续匹配后续的部分。 对于没有任何匹配的情况,可以用fallthrough 语句。
switch i {
case 0: // empty case body
case 1:
f() // f is not called when i == 0!
}
case语句还可以带多个值:
switch i {
case 0, 1:
f() // f is called if i == 0 || i == 1.
}
case语句不一定必须是整数或整数常量。如果省略switch的 要匹配的值,那么case可以是任意的条件语言。
switch {
case i < 0:
f1()
case i == 0:
f2()
case i > 0:
f3()
}
++ 和 -- 不再是表达式,它们只能在语句中使用。因此, c = p++ 是错误的。语句 p++ 的含义也完全不同,在go中等价于 (*p)++ 。
defer可以用于指定函数返回前要执行的语句。
fd := open("filename")
defer close(fd) // fd will be closed when this function returns.