第 4 章 复合数据类型

《Go 程序设计语言》学习笔记目录

笔记来源:《Go 程序设计语言》ISBN:9787111558422 作者:Alan Donovan, Brianv Kernighan

4.1 数组

索引可以按照任意顺序出现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
type Currency int

const (
    USD Currency = iota
    EUR
    GBP
    RMB
)

func main() {
    symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"}
    fmt.Println(RMB, symbol[RMB]) // "3 ¥"
}

索引有的时候也可以省略

1
2
// 定义一个有100个元素的数组r,除了最后一个元素值是-1外,其他元素值都是0
r := [...]int{99: -1}

数组类型相同(值类型、长度都相同)的数组可以比较是否相等

1
2
3
4
5
6
7
8
9
func main() {
    a := [2]int{1, 2}
    b := [...]int{1, 2}
    c := [2]int{1, 3}
    fmt.Println(a == b, a == c, b == c) // "true false false"

    d := [3]int{1, 2}
    fmt.Printf(a == d) // 编译错误:无法比较 [2]int 和 [3]int
    }

Go 把数组和其他的类型都看成值传递

4.2 slice

slice 通常写成 []T

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func main() {
    months := [...]string{1: "一月", 2: "二月", 3: "三月",
        4: "四月", 5: "五月", 6: "六月",
        7: "七月", 8: "八月", 9: "九月",
        10: "十月", 11: "十一月", 12: "十二月"}

    slicemonths := months[1:13]
    fmt.Printf("months[1:13] %v\n", slicemonths)
    slicemonthsStart := months[1:]
    fmt.Printf("months[1:] %v\n", slicemonthsStart)
    sliceAll := months[:]
    fmt.Printf("months[:] %v\n", sliceAll)

    Q2 := months[4:7]
    summary := months[6:9]
    fmt.Printf("二季度 %v len=%v cap=%v\n", Q2, len(Q2), cap(Q2))
    fmt.Printf("夏天 %v len=%v cap=%v\n", summary, len(Q2), cap(summary))
}

slice 操作符 s[i:j] 创建了一个新的 slice

  • 0 ≤ i ≤ j ≤ cap(s)
  • 这个新的 slice 引用了序列 s 中 从 i 到 j - 1 索引位置的所有元素
  • s 可以是:数组、指向数组的指针、slice
  • 新 slice 的元素个数是 j - i 个
  • 如果上面的表达式中省略了 i,那么新 slice 的起始索引位置就是 0
  • 如果省略了 j,那么新的 slice 的结束索引位置是 len(s) - 1,即 j = len(s)
  • 因此 slicemonths[1:13] 引用了所有有效月份,同样的写法也可以是 slicemonths[1:]
  • slicemonth[:] 引用了整个数组

反转数组 gop1.io/ch4/rev

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
    a := [...]int{0, 1, 2, 3, 4, 5}
    // 反转整个数组
    reverse(a[:])
    fmt.Println(a) // "[5 4 3 2 1 0]"
}

func reverse(s []int) {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
}

slice 唯一允许的比较操作是和 nil 比较,例如

1
if summer == nil { /* ... */}

检查一个 slice 是否为空

  • 使用 len(s) == 0
  • 而不是 s == nil,因为 s != nil 的情况下,slice 也可能是空的
1
2
3
4
var s []int    // len(s) == 0, s == nil
s = nil        // len(s) == 0, s == nil
s = []int[nil] // len(s) == 0, s == nil
s = []int{}    // len(s) == 0, s != nil

内置函数 make 创建 slice

  • make([]T, len) // 长度和容量相等
  • make([]T, len, cap) 和 make([]T, cap)[:len] 功能相同

4.2.1 append 函数

内置函数 append 用来将元素追加到 slice 的后面

1
2
3
4
5
var runes []rune
for _, r := range "Hello, 世界" {
    runes = append(runes, r)
}
fmt.Printf("%q\n", runes) // ['H' 'e' 'l' 'l' 'o' ',' ' ' '世' '界']

内置 copy 函数用来复制 slice

4.2.2 slice 就地修改

comments powered by Disqus