Go Slice 秘籍实战


参考:

[译]Go Slice 秘籍


2023.02.25补记:

目前Go官方新增了slices包(从之前实验性的exp中迁过来了一部分)

issue/57433

slices: new package



Cut 切掉一段数据


1
a = append(a[:i], a[j:]...)

切掉[i,j)之间的元素

如:

1
2
3
4
5
6
7
8
9
10
11
12
func cut() {

//切掉一段数据
a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}

a = append(a[:1], a[4:]...)

fmt.Println(a)
}

//------------
//[0 400 500 600 700 800 900 1000]


Delete 删除某个元素


注: 官方已有实现 src/slices/slices.go#L106


1
a = append(a[:i], a[i+1:]...)

删掉第i个元素

1
2
3
4
5
6
7
8
9
10
func delete() {

a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}
a = append(a[:2], a[2+1:]...)

fmt.Println(a)
}

//-----------
//[0 100 300 400 500 600 700 800 900 1000]



Expand 插入一段到中间


1
a = append(a[:i], append(make([]T, j), a[i:]...)...)

a = append(a[:i], append(make([]T, j), a[i:]…)…)

其中,i为插入的位置,j为插入元素的个数;

即:在i位置后面,插入j个对应元素的空值

1
2
3
4
5
6
7
8
9
10
func expand() {
a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}

//i=4,j=8,i为插入的位置,j为插入的元素个数
a = append(a[:4], append(make([]int, 8), a[4:]...)...)
fmt.Println(a)
}

//------------
//[0 100 200 300 0 0 0 0 0 0 0 0 400 500 600 700 800 900 1000]



Extend 插入一段到尾部


1
a = append(a, make([]T, j)...)

在原切片后面,插入j个对应元素的空值

1
2
3
4
5
6
7
8
9
func extend() {
a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}

a = append(a, make([]int, 3)...)
fmt.Println(a)

}
//--------------
//[0 100 200 300 400 500 600 700 800 900 1000 0 0 0]



Insert 插入某个元素到指定的位置


注: 官方已有实现 src/slices/slices.go#L83


1
a = append(a[:i], append([]T{x}, a[i:]...)...)

在i位置处,插入(挤进)一个新元素x

1
2
3
4
5
6
7
8
func insert(){
a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}
//i=3,x=10086
a = append(a[:3], append([]int{10086}, a[3:]...)...)
fmt.Println(a)
}
//-----------
//[0 100 200 10086 300 400 500 600 700 800 900 1000]


InsertVector 插入某个切片到指定的位置


注: 官方库的Insert src/slices/slices.go#L83支持插入多个元素 ,相当于也实现了InsertVector


1
a = append(a[:i], append(b, a[i:]...)...)

在i位置处,插入(挤进)一个(同类型的)新切片b

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func insertvector() {

a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}

b := []int{-280, -975, -764}

//i=6
a = append(a[:], append(b, a[6:]...)...)
fmt.Println(a)

}

//-----------
//[0 100 200 300 400 500 600 700 800 900 1000 -280 -975 -764 600 700 800 900 1000]


Pop 从切片中取出最后一个元素


1
x, a := a[len(a)-1], a[:len(a)-1]

从切片a中”切除”最后一个元素,返回最后一个元素x,和切除最后一个元素后的切片a


append()的反操作


1
2
3
4
5
6
7
8
9
10
11
12
func pop() {

a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}

x, a := a[len(a)-1], a[:len(a)-1]
fmt.Println(a)
fmt.Println(x)

}
//------------------
//[0 100 200 300 400 500 600 700 800 900]
//1000


Shift 从切片中”切除”第一个元素


1
x, a := a[0], a[1:]

从切片a中切除第一个元素,返回第一个元素x,和切除第一个元素之后的切片a


1
2
3
4
5
6
7
8
9
func shift() {
a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}
x, a := a[0], a[1:]
fmt.Println(a)
fmt.Println(x)
}
//------------
//[100 200 300 400 500 600 700 800 900 1000]
//0


Unshift 从切片中”切除”第一个元素


1
a = append([]T{x}, a...)

将元素x插入到切片的开头

也算是append()的反操作


1
2
3
4
5
6
7
8
9
func unshift() {
a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}
//x为271828
a = append([]int{271828}, a...)
fmt.Println(a)

}
//------------------
//[271828 0 100 200 300 400 500 600 700 800 900 1000]


Reverse 反转切片中的元素


注: 已有提案在实现这个func


1
2
3
4
for i := len(a)/2-1; i >= 0; i-- {
opp := len(a)-1-i
a[i], a[opp] = a[opp], a[i]
}

1
2
3
for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
a[left], a[right] = a[right], a[left]
}

反转切片中的元素


1
2
3
4
5
6
7
8
9
10
func reverse() {
a := []int{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}
for i := len(a)/2 - 1; i >= 0; i-- {
opp := len(a) - 1 - i
a[i], a[opp] = a[opp], a[i]
}
fmt.Println(a)
}
//---------------
//[1000 900 800 700 600 500 400 300 200 100 0]

也已经有提案来实现两个切片之间的交集