目录

Go 容器

各种类型的变量能满足一般的编程需求,但是应对复杂算法时,就需要用到容器了。

在很多语言里,容器是以标准库的方式提供,你可以随时查看这些标准库的代码,了解如何创建/删除/维护内存。

  • C语言没有提供容器封装,开发者需要自己根据性能需求进行封装,或者使用第三方提供的容器

  • C++ 语言的容器通过标准库提供,如vector对应数组,list对应双链表,map对应映射等

  • C# 语言通过 .NET 框架提供,如 List 对应数组,LinkedList 对应双链表,Dictionary对应映射

  • Lua 语言的 table 实现了数组和映射的功能,Lua 语言默认没有双链表支持

Go里面将几种常用的容器内置了。

数组

var a [6]int                            // 长度为 6 的空数组
primes := [6]int{ 2, 3, 5, 7, 11, 13 }  //
var ipv4 = [...]uint8{192, 168, 0, 1}   // 由编译器自己计算长度

var b [2]string
b[0] = "Hello"
b[1] = "World"

a == primes                             // 比较两个数组相等: 长度 和 所有元素 一致

切片

切片的底层结构包括三部分:起始地址 + 大小 + 容量。把数组比作一块完整的切糕的话,切片就是你要的“那一块”,切的过程包含“从哪里开始”及“切多大”,容量可以理解最多能切多大。

primes := [6]int{2, 3, 5, 7, 11, 13}        // 数组

切片操作arr[low:high]: 范围是 low <= index < high
切片长度len:切片包含的元素个数
切片容量cap:从第一个元素开始数,到其底层数组元素末尾的个数

fmt.Println(primes[1:4], len(primes[1:4]), cap(primes[1:4]) ) // [3 5 7] 3 5
fmt.Println(primes[:4], len(primes[:4]), cap(primes[:4]) )    // [2 3 5 7] 4 6 省略 low ,默认取 0
fmt.Println(primes[1:], len(primes[1:]), cap(primes[1:]) )    // [3 5 7 11 13] 5 5 省略 high,默认取 len(a)
fmt.Println( primes[1:4], (primes[1:4])[1:2] )                // [3 5 7] [5] 切了后 再切 ^_^

数组也可以不显示定义:

abc := []int{2, 3, 5, 7, 11, 13}            // 底层实际构建了一个数组

也可以使用 make([]Type, len, cap) 创建切片

edf := make([]int, 5, 5)                       // [0, 0, 0, 0, 0]

往切片追加值,当切片的底层数组大小不足,容不下追加的值时,Go底层会分配一个更大的数组,然后将数据复制一份到新数组上。最后,返回的是新数组上的切片 ^_^

s := primes[1:4]
s = append( s, 100, 102, 103, 104, 105 )
fmt.Println(s)          // [3 5 7 100 102 103 104 105]
fmt.Println(primes)     // [2 3 5 7 11 13]

拷贝操作copy( destSlice, srcSlice []T) int:

slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 复制 slice1 到 slice2,长度限制,只复制了 3 个元素
copy(slice1, slice2) // 复制 slice2 到 slice1 的前3个位置

Map

fmt.Println( map[string]bool{"192.168.0.101":true} )  // 字面量 map[192.168.0.1:true]

var ipSwitches = map[string]bool{}

ipSwitchs["192.168.0.1"] = true

delete(ipSwitchs, "192.168.0.1")        // 删除元素
type Vertex struct {
    Lat, Long float64
}

m := map[string]Vertex{}            // 声明
n := make( map[string]Vertex )      // make 式声明,等价上句,作用是一样的

m["Bell Labs"] = Vertex{ 40.68433, -74.39967 }

m[key] = elem           // 新增 or 修改
a = m[key]              // 获取
b, ok = m[key]          // 如果 key 在 m 中,则 ok 为 true;否则 ok 为 false, b 为零值

遍历 For Range

用于遍历 Array SliceMap

pow := []int {1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {                 // 依次将下标 和 值 复制 给 i 和 v
    fmt.Printf("pow[%d] = %d\n", i, v)
}
for _, v := range pow { ... }           // 不复制 下标
for i, _ := range pow { ... }           // 不复制 值
for i := range pow { ... }              // 不复制 值,简写版

List

new 与 make

new操作用于基本类型和struct自定义类型,返回的是指针:

var sum *int
sum = new(int) //分配空间
*sum = 98
fmt.Println(*sum)

type Student struct {
    name string
    age int8
}
var s *Student
s = new(Student)
s.name = "codekissyoung"
fmt.Printf("type : %T value: %v", s, s)

make专门用于 Slice map chan 容器,分配及初始化它们的结构和数据,返回的是引用,即 Type 本身。