说明
本章主要说明Go语言中的复杂结构
下面的示例代码来自于这里
指针
声明
指针保存了变量的内存地址
类型 *T 是指向类型 T 的值的指针。其零值是
nil
var p *int
&
符号会生成一个指向其作用对象内存地址的指针
i := 42
p = &i
间接引用
*
符号表示指针指向的底层的值,即“间接引用”或“非直接引用”
package main
import "fmt"
func main() {
i := 10
p := &i
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i
fmt.Println(i)
}
- Go 没有指针运算
结构体
声明
- 一个结构体(
struct
)就是字段的集合,使用type
和struct
关键字来声明
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}
结构体内字段
- 结构体字段使用点号来访问
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
- 结构体内的字段赋值,可参考如下代码:
package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // 类型为 Vertex
v2 = Vertex{X: 1} // Y:0 被省略
v3 = Vertex{} // X:0 和 Y:0
)
func main() {
fmt.Println(v1, v2, v3)
}
结构体指针
- 结构体字段可以通过结构体指针来访问
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9// 此处并非是*p.X = 1e9
fmt.Println(v)
}
- 特殊的前缀 & 返回一个指向结构体的指针,因此也可以直接这样写:
p := &Vertex{1, 2} // 类型为 *Vertex
数组
声明
- 类型 [n]T 是一个有 n 个类型为 T 的值的数组,表达式:
var a [10]int
- 数组的长度是其类型的一部分,因此数组不能改变大小
赋值
- 对数组的值操作的代码如下:
package main
import "fmt"
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)
}
切片
声明
- 一个 slice 会指向一个序列的值,并且包含了长度信息,[]T 是一个元素类型为 T 的切片
package main
import "fmt"
func main() {
p := []int{2, 3, 5, 7, 11, 13}
fmt.Println("p ==", p)
for i := 0; i < len(p); i++ {
fmt.Printf("p[%d] == %d\n", i, p[i])
}
}
对slice切片
- slice 可以重新切片,创建一个新的 slice 值指向相同的数组,表达式:
s[lo:hi]
表示从 lo 到 hi-1 的 slice 元素,含两端,该切片的长度为 hi - lo
,因此s[lo:lo]
是空的。而s[lo:lo+1]
有一个元素,下面的代码是一个对slice切片的具体示例
package main
import "fmt"
func main() {
p := []int{2, 3, 5, 7, 11, 13}
fmt.Println("p ==", p)
fmt.Println("p[1:4] ==", p[1:4])
// 省略下标代表从 0 开始
fmt.Println("p[:3] ==", p[:3])
// 省略上标代表到 len(s) 结束
fmt.Println("p[4:] ==", p[4:])
}
构造 slice
- slice 由函数 make 创建。这会分配一个零长度的数组并且返回一个 slice
a := make([]int, 5) // len(a)=5
- 为了指定容量,可传递第三个参数到
make
:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
向 slice 添加元素
- 向 slice 添加元素是一种常见的操作,因此 Go 提供了一个内建函数
append
,表达式为:
func append(s []T, vs ...T) []T
append 的第一个参数 s 是一个类型为 T 的数组&切片,其余类型为 T 的值将会添加到 slice并返回
package main
import "fmt"
func main() {
var a []int
printSlice("a", a)
// append works on nil slices.
a = append(a, 0)
printSlice("a", a)
// the slice grows as needed.
a = append(a, 1)
printSlice("a", a)
// we can add more than one element at a time.
a = append(a, 2, 3, 4)
printSlice("a", a)
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %v\n",
s, len(x), cap(x), x)
}
坑
slice与数组的区别是它不声明长度
len表示长度,cap表示容量,cap必须大于等于len,以下代码是错误的
a := make([]int,10,3)
- slice 的零值是
nil
,一个 nil 的 slice 的长度和容量是 0