Golang指南
Go 富有表现力、简洁、干净且高效。它的并发机制使编写程序变得容易,从而充分利用多核和网络机器,而其新颖的类型系统则实现了灵活和模块化的程序构建。Go 可以快速编译为机器代码,但具有垃圾回收的便利性和运行时反射的强大功能。它是一种快速的、静态类型的编译语言,感觉就像一种动态类型的解释型语言。

每个Go 程序都是由构成的。程序从main包开始执行。并默认执行包中的main函数。

packages.go
1
2
3
4
5
6
7
package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}

导入

使用import关键字导入包。

1
import "fmt"

也可以使用圆括号来导入多个包。例如:

1
2
3
4
import (
"fmt"
"math/rand"
)

按照约定,包名和导入路径的最后一个元素一致,例如,math/rand包中的源码均以rand作为包名。

导出

在Go 中,如果一个名字已大写字母开头,则该名字是导出的。例如:Pi是个导出的名字,它导出自math包。
在导入一个包时,你只能访问该包导出的名字,任何未导出的名字在该包外都无法访问。

同一包中的导出名是唯一的。

函数

使用func关键字定义函数。
语法:

1
2
3
func 函数名称([参数]) [返回类型] {
[return 语句]
}

例如:

1
2
3
func add(x, y int) int {
return x + y
}

函数可以没有参数或者接受多个参数。注意类型在变量名之后
当连续两个或多个函数的已命名形参类型相同时,除最后一个类型以外,其它可以省略。例如:

1
x int, y int

可以写成:

1
x, y int

多值返回

函数可以没有返回值,或者返回一个或多个值。例如:

multiple-results.go
1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func swap(x, y string) (string, string) {
return y, x
}

func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}

swap函数返回了两个字符串。

命名返回值

Go的返回值可以被命名,它们会被视作定义在函数顶部的变量。
没有参数的return语句返回已命名的返回值。也就是直接返回

named-results.go
1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}

func main() {
fmt.Println(split(17))
}

变量

var关键字用于声明一个变量列表,跟函数的参数列表一样,类型在变量名之后。

variables.go
1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

// 定义变量
var c, python, java bool

func main() {
var i int
fmt.Println(i, c, python, java)
}
`var`语句可以出现在包或函数级别

变量的初始化

变量声明可以包含初始值,每个变量对应一个
如果初始值已存在,则可以省略类型,变量会从初始值中获取类型

variables-with-initializers.go
1
2
3
4
5
6
7
8
9
10
package main

import "fmt"

var i, j int = 1, 2

func main() {
var c, python, java = true, false, "no!"
fmt.Println(i, j, c, python, java)
}

短变量声明

在函数中,可在类型明确的地方使用:=语法声明变量。

short-variable-declarations.go
1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"

fmt.Println(i, j, k, c, python, java)
}
`:=`不能在函数外使用

基本类型

Go的基本类型有

1
2
3
4
5
6
7
8
9
10
11
12
13
bool

string

int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr

byte // alias for uint8
rune // alias for int32

float32 float64

complex64 complex128

int, uintuintptr 在 32 位系统上通常为 32 位宽,在 64 位系统上则为 64 位宽。 当你需要一个整数值时应使用 int 类型,除非你有特殊的理由使用固定大小或无符号的整数类型。

basic-types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"fmt"
"math/cmplx"
)

var (
toBe bool = false
maxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)

func main() {
fmt.Printf("Type: %T value: %v\n", toBe, toBe)
fmt.Printf("Type: %T value: %v\n", maxInt, maxInt)
fmt.Printf("Type: %T value: %v\n", z, z)
}

零值

没有明确初始化值的变量声明会被赋予它们的零值
数值类型的零值是0,布尔类型是false,字符串类型是””(空字符串)。

zero.go
1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

类型转换

表达式 T(v) 将表达式 v 转换为类型 T 的值。
例如:

1
2
3
var i int = 64
var f float64 = float64(i)
var u uint = uint(f)

或者

1
2
3
i := 64
f := float64(i)
u := uint(f)

Go在不同类型的项之间赋值时需要显示转换

类型推导

在声明一个变量而不指定其类型时(即使用不带类型的:=语法或var =表达式语法),变量的类型由右值推导得出。
当右值声明了类型时,新变量的类型与其相同

1
2
var i int
j := i // j 也是int类型

不过当右边包含未声明类型的数值常量时,新变量的类型就可能是intfloat64complex128。这取决于常量的精度。

1
2
3
i := 42             // int
f := 3.14 // float64
g := 0.5 + 1.0i // complex128

常量

常量的声明和变量类似,只不过使用const关键字。
常量可以是字符,字符串,布尔值或数值。
常量不能用:=语法声明。

constants.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

const Pi = 3.14

func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")

const Truth = true
fmt.Println("Go rules?", Truth)
}

数值常量

一个未指定类型的常量由上下文来决定其类型

numeric-constants.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import "fmt"

const (
// Big 将 1 左移 100 位来创建一个非常大的数字
// 即这个数的二进制是 1 后面跟着 100 个 0
Big = 1 << 100
// Small 再往右移 99 位,即 Small = 1 << 1,或者说 Small = 2
Small = Big >> 99
)

func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}

func main() {
fmt.Println(needInt(Small))
fmt.Println(needFloat(Small))
fmt.Println(needFloat(Big))
}