一、基本结构
hello world 程序:1
2
3
4
5
6
7package main
import "fmt"
func main(){
fmt.Println("你好,世界")
}
直接运行:1
2 go run hello.go
你好,世界
构建可执行程序:1
2
3 go build hello.go
./hello
你好,世界
PS
- Package 用于组织代码架构,类似于其他语言中的库或命名空间
- 每个 go 源文件都必须属于(且只属于一个)特定的 package,一个 package 可以包含多个 go 代码文件
- import 导入某个 package ,意味着获取了该 package 中可见对象的访问权限
- import 导入的 package 未在后面的代码中使用会报错,no unnecessary code! 原则
- main 函数没有任何参数且不返回任何值,它通常作为程序执行的入口
导入多个包:1
2
3
4import (
"fmt"
"os"
)
二、变量
变量定义和赋值:var identifier [type] = value
1
2
3
4
5var a int
var b bool
var str string = "hello"
var i = 5
GOROOT := os.Getenv("GOROOT")
PS
b := false
等同于var b = false
。借助 Go 语言的类型推断可以省略类型声明:=
或者var
形式的变量赋值,包含变量初始化动作。即a = 1
表示将 1 赋值给变量 a(a 必须已经创建),a := 1
表示新建变量 a,并将 1 赋值给 a。- 使用未定义的变量,定义的本地变量未在后续代码中使用,新建变量的名称已存在等都会报错
- 推荐使用
:=
的形式,但只应该在函数内部使用
三、字符串
连接字符串,+
:1
2
3s := "hel" + "lo"
s += " world"
fmt.Println(s) // prints out "hello world"
- 前缀匹配:
strings.HasPrefix(s, prefix string) bool
- 后缀匹配:
strings.HasSuffix(s, suffix string) bool
- 包含关系:
strings.Contains(s, substr string) bool
- 字符串替换:
strings.Replace(str, old, new, n) string
- 计算子字符串出现次数:
strings.Count(s, str string) int
- 分割字符串:
strings.Split(s, sep string) []string
- join 字符串:
strings.join(sl []string, sep string) string
示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package main
import (
"fmt"
"strings"
)
func main() {
str := "The quick brown fox jumps over the lazy dog"
sl := strings.Split(str, " ")
fmt.Printf("Splitted in slice: %v\n", sl)
// 字符串分割后的返回值 sl 是数组
for _, val := range sl {
fmt.Printf("%s,", val)
}
fmt.Println()
str2 := strings.Join(sl, "/")
fmt.Printf("sl joined by / is: %s\n", str2)
}
// output
// Splitted in slice: [The quick brown fox jumps over the lazy dog]
// The,quick,brown,fox,jumps,over,the,lazy,dog,
// sl joined by / is: The/quick/brown/fox/jumps/over/the/lazy/dog
四、控制结构
if-else
if-else 结构语法如下:1
2
3
4
5
6
7if condition1 {
// do something
} else if condition2 {
// do something
} else {
// catch-all or default
}
PS:else
旁边的 }
和 {
不能隔行,否则无法编译通过。
switch
1 | switch var1 { |
1 | switch { |
1 | switch initialization { |
示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package main
import (
"fmt"
)
func Abs(x int) int {
if x < 0 {
return -x
}
return x
}
func main() {
switch num := Abs(-5); {
case num > 0:
fmt.Println("Result is positive")
case num < 0:
fmt.Println("Never gonna happen")
default:
fmt.Println("Exact 0")
}
}
// Result is positive
for
参考如下示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package main
import (
"fmt"
)
func main() {
str := "Go is a beautiful language"
for ix :=0; ix < len(str); ix ++ {
fmt.Printf("Character on position %d is: %c \n", ix, str[ix])
}
for pos, char := range str {
fmt.Printf("Character on position %d is: %c \n", pos, char)
}
}
五、函数
定义函数语法:1
2func g() {
}
注意不能写成如下形式:1
2
3func g()
{
}
函数调用语法:pack1.Function(arg1,arg2, ... ,argn)
Go 中的函数可以接收另一个函数作为参数,比如有下面两个函数:f1(a, b, c int)
接收三个参数f2(a, b int) (int, int, int)
有两个参数和三个返回值
则可以这样调用:f1(f2(a, b))
函数本身可以赋值给变量,如 add := binOp
参数与返回值
Go 中的函数可以接收 0 个或多个参数,返回 0 个或多个结果。
传给函数的参数通常会有名称,但是也可以没有名称只包含类型:func f(int, int, float64)
Go 函数的传参默认是按值传递,即实际传给函数的是参数值的复制。如调用 Function(arg1)
,函数 Function
收到的是 arg1
指向的值的副本,而不是 arg1
本身。
如果需要函数操作传入的参数本身,即 Function(arg1)
操作 arg1 本体的值,则需要传入参数的指针(内存地址)。使用如下形式:Function(&arg1)
。
大部分函数都需要返回值,可以是命名的也可以不命名。
数量未知的参数
函数的最后一个参数可以是 ...type
这样的形式,即 func myFunc(a, b, arg ...int) {}
。这表示函数可以接收相同类型的不定数量的参数。参考如下示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29package main
import (
"fmt"
)
func main() {
x := Min(1, 3, 2, 0)
fmt.Printf("The minimum is: %d\n", x)
arr := []int{7, 9, 3, 5, 1}
x = Min(arr...)
fmt.Printf("The minimum in the array arr is: %d", x)
}
func Min(a ...int) int {
if len(a) == 0 {
return 0
}
min := a[0]
for _, v := range a {
if v < min {
min = v
}
}
return min
}
// The minimum is: 0
// The minimum in the array arr is: 1
Defer
defer
关键字用于“延迟”执行某个函数或命令,由 defer
修饰的语句会在外部函数返回结果之后再执行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package main
import (
"fmt"
)
func main() {
fmt.Printf("In Main function at the top\n")
defer Function2()
fmt.Printf("In Main function at the bottom\n")
}
func Function2() {
fmt.Printf("Function2: Deferred until the end of the calling function")
}
// In Main function at the top
// In Main function at the bottom
// Function2: Deferred until the end of the calling function%
如果 defer
语句中包含变量参数,则该参数的值在 defer
的位置已经确定。参考如下代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14package main
import (
"fmt"
)
func main() {
i := 0
defer fmt.Println(i)
i++
fmt.Println("The number is:")
}
// The number is:
// 0
由 defer
修饰的 Println
函数虽然在程序执行流的最后输出 i
值。但变量 i
在 defer
处的值为 0,因此最后输出 0 而不是执行 i++
后的 1 。
当代码中包含有多个 defer
语句时,这些语句会以 LIFO(后进先出,类似 stack)的顺序执行。1
2
3
4
5
6
7
8
9
10
11
12package main
import (
"fmt"
)
func main() {
for i := 0; i < 5; i++ {
defer fmt.Printf("%d", i)
}
}
// 43210
递归函数
1 | package main |
高阶函数
函数作为参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package main
import "fmt"
func main() {
callback(1, Add)
}
func Add(a, b int) {
fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b)
}
func callback(y int, f func(int, int)) {
f(y, 2)
}
// => The sum of 1 and 2 is: 3
(匿名)函数赋值给变量1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package main
import "fmt"
func main() {
for i := 0; i < 4; i++ {
g := func(i int) { fmt.Printf("%d", i) }
g(i)
fmt.Printf(" - g is of type %T and has value %v\n", g, g)
}
}
// => 0 - g is of type func(int) and has value 0x4839d0
// => 1 - g is of type func(int) and has value 0x4839d0
// => 2 - g is of type func(int) and has value 0x4839d0
// => 3 - g is of type func(int) and has value 0x4839d0
函数作为返回值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package main
import "fmt"
func main() {
p2 := Add2()
fmt.Printf("Call Add2 for 3 returns: %v\n", p2(3))
TwoAdder := Adder(2)
fmt.Printf("The result is: %v\n", TwoAdder(3))
}
func Add2() func(b int) int {
return func(b int) int {
return b + 2
}
}
func Adder(a int) func(b int) int {
return func(b int) int {
return a + b
}
}
// => Call Add2 for 3 returns: 5
// => The result is: 5
另一个版本的累加器,涉及到闭包:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package main
import "fmt"
func main() {
f := Adder()
fmt.Print(f(1), " - ")
fmt.Print(f(20), " - ")
fmt.Print(f(300))
}
func Adder() func(int) int {
var x int
return func(delta int) int {
x += delta
return x
}
}
// => 1 - 21 - 321
参考资料
The Way To Go: A Thorough Introduction To The Go Programming Language