golang 中 map, slice(切片) 是常用的类型, slice 是对数组进行封装, 可以避免一些坑
- package main
- import (
- "fmt"
- "strconv"
- )
- func testLenCap() {
- strs := make([]string, 5, 10) // 可以只有一个数字参数, 那么 cap=len, make([]string, 5, 5) 等价于 make([]string, 5)
- fmt.Printf("value=%v, is nil=%v\n", strs, strs == nil)
- //strs := []string{"0", "1", "2", "3", "4"} // 当然这种方式是直接赋值了, 忽略赋值等价于 make([]string, 5)
- for i := 0; i < len(strs); i++ {
- strs[i] = strconv.Itoa(i)
- }
- fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs), cap(strs), &strs, strs) //%p 内存地址
- for i := len(strs); i < cap(strs); i++ {
- //strs[i] = strconv.Itoa(i) //panic
- strs = append(strs, strconv.Itoa(i)) // 使用 append 向数组追加数据
- }
- fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs), cap(strs), &strs, strs) // 内存地址不变
- strs = append(strs, "10")
- fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs), cap(strs), &strs, strs) // 内存地址改变
- //strs2 自身的地址与 strs 不一样, 但实际数组的内存地址不变, 改变 strs, strs2 其中任意一个变量, 另一个随之改变
- strs2 := strs[:]
- fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs2), cap(strs2), &strs2, strs2)
- strs2[5] = "1000"
- fmt.Printf("strs[5]=%s\n", strs[5])
- //strs3 自身的地址与 strs 不一样, 实际数组的内存地址也不一样, 互不干扰.
- startIndex := 5
- strs3 := strs[startIndex:7]
- fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs3), cap(strs3), &strs3, strs3)
- fmt.Printf("cap(strs3) == cap(strs)-startIndex : %v", cap(strs3) == cap(strs)-startIndex)
- }
- func main() {
- testLenCap()
- }
控制台打印结果:
- value=[ ], is nil=false
- len=5, cap=10, strsAddress=0xc0420023e0, valueAddress=0xc04203e0a0
- len=10, cap=10, strsAddress=0xc0420023e0, valueAddress=0xc04203e0a0
- len=11, cap=20, strsAddress=0xc0420023e0, valueAddress=0xc042040140
- len=11, cap=20, strsAddress=0xc0420024a0, valueAddress=0xc042040140
- strs[5]=1000
- len=2, cap=15, strsAddress=0xc0420024e0, valueAddress=0xc042040190
- cap(strs3) == cap(strs)-startIndex : true
可以看到:
len 函数是实际数据存长度;
cap 是最大容量, 可以避免反复分配内存;
扩容机制是翻倍, 所以 go 的扩容很快, 尤其是基数很大的情况下. 但如果能预先分配 cap, 即使再快也是无畏的消耗
使用原切片创建新切片时, 应注意每个切片的值, 避免出现与预想不一样的情况
来源: http://www.bubuko.com/infodetail-2982149.html