#《Go 语音圣经(中文版)》

顺便熟悉一下vim的技巧吧!

#入门

#Hello World

1
2
3
4
5
6
7
8
9
// go-bible/ch1/helloworld.go

package main

import "fmt"

func main() {
fmt.Println("Hello, 世界")
}
1
2
[10:58:11] onns@Onns ~/Documents/code/go/go-bible/ch1 $ go run helloworld.go
Hello, 世界

Go语言原生支持Unicode,它可以处理全世界任何语言的文本。

go run会编译.go文件并且直接运行可执行文件结果,如果要保存编译结果,使用go build

1
2
3
[10:58:53] onns@Onns ~/Documents/code/go/go-bible/ch1 $ go build helloworld.go
[10:59:17] onns@Onns ~/Documents/code/go/go-bible/ch1 $ ./helloworld
Hello, 世界

每个源文件都以一条package声明语句开始,这个例子里就是package main,表示该文件属于哪个包。

main包比较特殊。它定义了一个独立可执行的程序,而不是一个库。

必须恰当导入需要的包,缺少了必要的包或者导入了不需要的包,程序都无法编译通过。

Go语言编译过程没有警告信息,争议特性之一。

import声明必须跟在文件的package声明之后。

一个函数的声明由func关键字、函数名、参数列表、返回值列表以及包含在大括号里的函数体组成。

Go语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。

编译器会主动把特定符号后的换行符转换为分号,因此换行符添加的位置会影响Go代码的正确解析。

函数的左括号{必须和func函数声明在同一行上,且位于末尾,不能独占一行,而在表达式x + y中,可在+后换行,不能在+前换行。

Go 语言在代码格式上采取了很强硬的态度。gofmt工具把代码格式化为标准格式(这个格式化工具没有任何可以调整代码格式的参数)。

go工具中的fmt子命令会对指定包(否则默认为当前目录)中所有.go源文件应用gofmt命令:

1
2
3
[10:57:14] onns@Onns ~/Documents/code/go/go-bible/ch1 $ go fmt
helloworld.go
[10:58:10] onns@Onns ~/Documents/code/go/go-bible/ch1 $ go fmt

只有那些不规范的文件会被列出,第二次再运行就不会格式化已经符合规则的文件。

#命令行参数

区间索引时,Go言里也采用左闭右开形式,即,区间包括第一个索引元素,不包括最后一个。

程序导入包时可以用括号把它们括起来写成列表形式,也可以分开写成独立的import声明,两种形式都合法,列表形式习惯上用得多。

包导入顺序并不重要,gofmt工具格式化时按照字母顺序对包名排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// go-bible/ch1/echo1.go
package main

import (
"fmt"
"os"
)

func main() {
var s,sep string
for i := 1; i < len(os.Args); i++ {
s += sep + os.Args[i]
sep = " "
}
fmt.Println(s)
}

变量会在声明时直接初始化。如果变量没有显式初始化,则被隐式地赋予其类型的零值(zero value),数值类型是0,字符串类型是空字符串""

:=是短变量声明(short variable declaration)的一部分,这是定义一个或多个变量并根据它们的初始值为这些变量赋予适当类型的语句。

i++/i--是语句,而不像 C 系的其它语言那样是表达式。所以j = i++非法。

++--都只能放在变量名后面,因此--i也非法。

1
2
3
for initialization; condition; post {
// zero or more statements
}

for循环三个部分不需括号包围。

大括号强制要求,左大括号必须和post语句在同一行。

initialization语句是可选的,在循环开始前执行。

initalization如果存在,必须是一条简单语句(simple statement),即短变量声明自增语句赋值语句函数调用

condition是一个布尔表达式(boolean expression)。

for循环的这三个部分每个都可以省略,如果省略initializationpost,分号也可以省略:

1
2
3
4
// a traditional "while" loop
for condition {
// ...
}

全省略:

1
2
3
4
// a traditional infinite loop
for {
// ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// go-bible/ch1/echo2.go

package main

import (
"fmt"
"os"
)

func main() {
s,sep := """"
for _,arg := range os.Args[1:] {
s += sep + arg
sep = " "
}
fmt.Println(s)
}

每次循环迭代,range产生一对值:索引以及在该索引处的元素值

Go语言不允许使用无用的局部变量(local variables),因为这会导致编译错误。解决方法是用空标识符(blank identifier),即_(也就是下划线)。

s := ""是一条短变量声明,最简洁,但只能用在函数内部,而不能用于包变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
// go-bible/ch1/echo3.go

package main

import (
"fmt"
"os"
"strings"
)

func main() {
fmt.Println(strings.Join(os.Args[1:], " "))
}
1
2
3
4
5
6
7
8
9
10
11
12
// go-bible/ch1/echo4.go

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println(os.Args[1:])
}
1
2
3
4
5
6
[14:50:04] onns@Onns ~/Documents/code/go/go-bible/ch1 $ ./echo2 123 456
123 456
[14:58:44] onns@Onns ~/Documents/code/go/go-bible/ch1 $ ./echo3 123 4 5 6
123 4 5 6
[14:58:58] onns@Onns ~/Documents/code/go/go-bible/ch1 $ ./echo4 123 4 5 6
[123 4 5 6]