golang 中的切片

1. 切片的结构定义,即 reflect.SliceHeader

type SliceHeader struct {
    Data uintptr        // 切片指向底层字节数组
    Len int            // 切片的字节长度
    Cap int            // 切片指向的内存空间的最大容量(对应元素的个数,不是字节数)
}

2. 切片的定义方式

var (
    a []int                    // nil 切片,和nil相等,一般用来表示一个不存在的切片
    b = []int{}                // 空切片,和 nil 不相等,一般用来表示一个空的集合
    c = []int{1, 2, 3}         // 有3个元素的切片,len和cap都为
    d = c[:2]                  // 有2个元素的切片,len为2,cap为3
    e = c[0:2:cap(c)]          // 有2个元素的切片,len为2,cap为3
    f = c[:0]                  // 有0个元素的切片,len为0,cap为3
    g = make([]int, 3)         // 有3个元素的切片,len和cap都为3
    h = make([]int, 2, 3)      // 有2个元素的切片,len为2,cap为3
    i = make([]int, 0, 3)      // 有0个元素的切片,len为0,cap为3
)

3. 遍历切片的方式

import (
    "fmt"
)

// 1. i 为键
for i := range a {
    fmt.Printf("a{%d}: %d\n", i, a[i])
}

// 2. i,v 分别为键值对
for i, v := range a {
    fmt.Printf("a{%d}: %d\n", i, v)
}

// 3. 
for i := 0; i < len(c); i++ {
    fmt.Printf("a{%d}: %d\n", i, a[i])
}

4. 添加切片元素

4.1 在切片的尾部追加 N 个元素

var a []int
a = append(a, 1)                    // 追加一个元素
a = append(a, 1, 2, 3)              // 追加多个元素,手写解包方式
a = append(a, []int{1, 2, 3}...)    // 追加一个切片,切片需要解包

4.2 在切片的开头添加元素

// 注:在开头一般都会导致内存的重新分配,而且会导致已有的元素全部复制一次。
// 因此,从切片的开头添加元素的性能一般要比从尾部追加元素的性能差很多

var a = []int{1, 2, 3}
a = append([]int{0}, a...)            // 在开头添加一个元素
a = append([]int{-3, -2, -1}, a...)   // 在开头添加一个切片

4.3 在切片的中间添加元素

// 注:每个添加操作中的第二个append()调用都会穿件一个临时切片
// 并将a[i:]的内容复制到新穿件的切片中
// 然后再将临时创建的切片追加到a[:i]zhong 

var a []int
a = append(a[:i], append([]int{x}, a[i:]...)...)        // 在第i个位置插入x
a = append(a[:i], append([]int{1,2,3}, a[i:]...)...)        // 在第i个位置插入切片

// 用 copy() 和 append()组合可以避免创建中间的临时切片
// 同样可以完成添加元素的操作
a = append(a, 0)            // 切片扩展一个空间
copy(a[i+1:], a[i:])        // a[i:]向后移动一个元素
a[i] = x                    // 设置新添加的元素

// 第一句中的append()用于扩展切片的长度,为要插入的元素留出空间
// 第二句中的copy()操作将要插入位置考试之后的元素向后挪动一个位置
// 第三局真实地将新添加的元素赋值到对应的位置


// 用 copy() 和 append() 实现在中间插入多个元素(一个切片)
a = append(a, x...)            // 为x切片扩展足够的空间
copy(a[i+len(x):], a[i:])      // a[i:]向后移动len(x)个位置
copy(a[i:], x)                 // 复制新添加的切片

5. 删除切片元素

5.1 从尾部删除(最快)

a = []int[1, 2, 3]
a = a[:len(a) - 1]        // 删除尾部1个元素
a = a[:len(a) - N)        // 删除尾部N个元素

5.2 从开头删除元素

a = []int{1, 2, 3}

// 1. 可以直接移动数据指针
a = a[1:]        // 删除开头1个元素
a = a[N:]        // 删除开头N个元素

// 2. 可以用append原地完成(原地完成时指
// 在原有的切片数据对应的内存区间内完成,不会导致内存空间结构的变化)
a = append(a[:0], a[1:]...)    // 删除开头1个元素
a = append(a[:0], a[N:]...)    // 删除开头N个元素

// 3. 也可以用 copy() 完成删除开头的元素
a = a[:copy(a, a[1:])]        // 删除开头1个元素
a = a[:copy(a, a[N:])]        // 删除开头N个元素

5.3 从中间删除元素

a = []int{1, 2, 3, ...}

// 1. 用 append() 完成
a = append(a[:i], a[i+1]...)        // 删除中间1个元素
a = append(a[:i], a[i+N]...)        // 删除中间N个元素

// 2. 用 copy() 完成
a = a[:i+copy(a[i:], a[i+1:])]        // 删除中间1个元素
a = a[:i+copy(a[i:], a[i+N:])]        // 删除中间N个元素

6. 切片内存技巧

切片高效操作的要点是:要降低内存分配的次数,尽量保证 append() 操作不会超出 cap 的容量,降低出发内存分配的次数和每次分配内存的大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值