Go 更多类型:指针、struct、slice 和映射
指针
Go 拥有指针。指针保存了值的内存地址。
类型 *T
是指向 T
类型值的指针。其零值为 nil
。
var p *int
&
操作符会生成一个指向其操作数的指针。
i := 42
p = &i
*
操作符表示指针指向的底层值。
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i
这也就是通常所说的“间接引用”或“重定向”。
与 C 不同,Go 没有指针运算。
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i
fmt.Println(p)
fmt.Println(*p)
*p = 21
fmt.Println(*p)
p = &j
*p /= 37
fmt.Println(j)
}
输出:
0xc00008e000
42
21
73
结构体
一个结构体(struct
)就是一组字段(field)。
package main
import "fmt"
type Vertex struct {
x int
y int
}
func main() {
fmt.Println(Vertex{
1, 2})
}
输出:
{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)
}
输出:
4
结构体指针
结构体字段可以通过结构体指针来访问。
如果我们有一个指向结构体的指针 p,那么可以通过 (*p).X
来访问其字段 X。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X
就可以。
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{
1, 2}
p := &v
p.X = 1e9
fmt.Println(v)
}
输出:
{1000000000 2}
结构体文法(Struct Literals)
结构体文法通过直接列出字段的值来新分配一个结构体。
使用 Name:
语法可以仅列出部分字段。(字段名的顺序无关。)
特殊的前缀 &
返回一个指向结构体的指针。
package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{
1, 2}
v2 = Vertex{
X: 1}
v3 = Vertex{
}
p0 = &Vertex{
Y: 1, X: 2}
)
func main() {
fmt.Println(v1, v2, v3, *p0)
}
输出:
{1 2} {1 0} {0 0} {2 1}
数组
类型 [n]T
表示拥有 n 个 T 类型的值的数组。
表达式
var a [10]int
会将变量 a 声明为拥有 10 个整数的数组。
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)
primes := [6]int{
2, 3, 5, 7, 11, 13}
fmt.Println(primes)
}
输出:
Hello World
[Hello World]
[2 3 5 7 11 13]
数组的长度是其类型的一部分,因此数组不能改变大小。这看起来是个限制,不过没关系,Go 提供了更加便利的方式来使用数组。
切片
每个数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。在实践中,切片比数组更常用。
类型 []T
表示一个元素类型为 T 的切片。(不写元素个数的数组)
切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔:
a[low : high]
它会选择一个半开区间,包括第一个元素,但排除最后一个元素。
以下表达式创建了一个切片,它包含 a 中下标从 1 到 3 的元素:
a[1:4]
package main
import "fmt"
func main() {
primes := [6]int{