四种复合数据类型,分别是数组、slice、map 和结构体。
数组和结构体都是聚和类型,他们的值由内存中的一组变量构成。数组和结构体的长度都是固定的。slice 和 map 都是动态数据结构,他们的长度在元素添加到结构时可以动态增长。
q := […]int{1,2,3} // 说明数组的长度由初始化数组的元素个数决定。
fmt.Printf(“%T\n”, q) // [3]int
数组的长度是数组类型的一部分,所以 [3]int 和 [4]int 是不同的数组类型。
r := […]int{99: -1}
定义了一个拥有100个元素的数组 r,除了最后一个元素值是 -1 外,该数组中的其他元素值都是 0。
如果一个数组的元素类型是可比较的,那么这个数组也是可比较的,这样我们就可以直接使用 == 比较两个数组的元素的值是否完全相同。
当调用一个函数的时候,每个传入的参数都会创建一个副本。Go把数组和其他的类型都看成值传递。
package main
import "fmt"
func change(ar [3]int) {
ar[0] = ar[0] + 1
}
func main() {
q := [...]int{1, 2, 3}
change(q)
fmt.Println(q[0])
}
slice 表示一个拥有相同类型元素的可变长度的序列。 slice 通常写成[]T,其中元素的类型都是 T; 它看上去像没有长度的数组类型。
slice 是一种轻量级的数据结构,可以用来访问数组的部分或者全部的元素。slice 有三个属性:指针、长度和容量。
slice 无法比较,不能用 == 比较两个 slice。
make 可以创建一个具有指定元素类型、长度和容量的 slice。
var runes[] rune
for _, r := range "Hello, 世界" {
runes = append(runes, r)
}
fmt.Printf("%q\n", runes)
rotate 和 reverse 可以就地修改 slice,传递给函数的 slice 变量在函数中修改后,返回后可以看到修改的值。这点和数组不一样。
map 的类型是 map[K]V, 其中 K 和 V是字典的键和值对应的数据类型。
内置函数 make 可以用来创建一个 map:
ages := make(map[string]int)
或者使用 map 的字面量。
ages := map[string]int {
"alice": 31,
"charlie": 34,
}
不可以获取 map 元素的地址,因为 map 的增长可能导致已有元素被重新散列到新的存储位置。
可以使用 for 循环(结合 range)来变量map 中所有的键和对应的值。
for name, age := range ages {
fmt.Printf("%s\t%d\n", name, age)
}
map 类型的零值是 nil,也就是说,没有引用任何散列表。
var ages map[string]int
fmt.Println(ages == nil) // "true"
fmt.Println(len(ages) == 0) // "true"
if age, ok := ages["bob"]; !ok {
}
和 slice 一样,map 不可比较。
type Employee struct {
ID int
Name string
}
type tree struct {
value int
left, right *tree
}
第一种:为每个成员变量指定一个值。
type Point struct{ X, Y int}
p := Point{1, 2}
第2种:通过指定部分或者全部成员变量的名称和值来初始化结构体变量。
gif.GIF{LoopCount: nframes}
大型结构体通常使用结构体指针的方式直接传递给函数或者从函数中返回。这种方式在函数需要修改结构体内容的时候也是必须的。
如果结构体所有的成员都可以比较,那么这个结构体就是可以比较的。
type Point struct {
X, Y int
}
type Circle struct {
Point
Radius int
}
可以访问
var c Circle
c.X = 8
构建
c = Circle{Point{8, 8}, 5}
Go 对象可以和 JSON 相互转换。Go 对象转成 JSON 成为 marshal。JSON 转换为 Go 对象为 unmarshal
模板是一个字符串或者文件,它包含一个或者多个两边用双大括号包围的单元–{{…}}, 这成为操作
。
TODO: