ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 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. 当用指针访问结构体的时候,我们用.代替-&gt;语法。 因此,用结构体类型和结构体指针类型访问结构体成员的语法是一样的。 ``` 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. ```