Go数组&切片使用
Hyman 2021/11/1 实践总结Go
# 声明
数组:
var array [size] string
1
切片:
var slice [] string
1
差异:数组的声明需要指定“size”,如果不指定就是为切片(slice)
# 初始化
数组:
var array1 = [3] string{"one", "two", "three"}
var array2 = [...] string{"one", "two", "three"}
array3 := [...] string{"one", "two", "three"} // 推荐:无需通过var声明
1
2
3
2
3
切片:
var slice [] string
slice = make([]string, 5, 5) // 指定长度为5,容量为5的切片
slice = make([]string,5) // 指定长度为5,容量为5的切片
slice2 := [] string{"one", "two", "three"} // 推荐:无需通过var声明
1
2
3
4
2
3
4
注:大部分情况下如果不知道切片长度,只要声明,无需初始化,单需要往切片增加数据是,通过append添加(声明的切面默认值是nil,但是append并不会异常)
# 常用操作
# 读取
数组
数组一般是在for循环中通过索引,或是range 直接读取:
aa := [5] string{}
for i, a := range aa { // aa的副本
fmt.Println("i= ", i, ", s=", a)
}
for i:=0; i< len(aa); i++ {
fmt.Println("i= ", i, ", s=", aa[i])
}
1
2
3
4
5
6
7
2
3
4
5
6
7
注意:
range 的是数组的副本,也是就是说会把aa拷贝一份,并且读取出来的项也是对应的副本,所以对项的修改是不会影响原有的数组,当aa比较大的时候会影响性能,所以可以采用读取数组指针的方式来优化:
for i, a := range &aa { // 这里拷贝的会是aa的指针
fmt.Println("i= ", i, ", s=", a)
}
1
2
3
2
3
切片
切片的读取和数组类似一般是在for循环中通过索引,或是range 直接读取:
aa := [] string{“hello”, "world"}
for i, a := range aa { // aa副本,但是由于切片时特殊的结构体,并不会保存整个数组,而是数据组第一个元素的地址,所以就算副本对性能也不会有太大影响
fmt.Println("i= ", i, ", s=", a)
}
for i:=0; i< len(aa); i++ {
fmt.Println("i= ", i, ", s=", aa[i])
}
1
2
3
4
5
6
7
2
3
4
5
6
7
注意:
切片和数组存在一些差异,切片range的时候拷贝的是slice的数据,底层还是共享数组,所以修改的时候回会影响原来slice
# 添加
数组:
一个数组中的元素个数总是恒定的,我们无法向其中添加元素,也无法从其中删除元素。但是元素可以通过索引修改值
aa := [5] string{}
aa[0] = "张三"
1
2
2
切片:
切片的底层实际上也是关联一个数组,所以如果新增元素超过数组的容量,内部会重新开辟一个数组大于(小于1024翻倍,大于增加25%)当前的数组
头部插入
aa := [] string{"张三", "李四"}
result := append([]string{"王五"}, aa...) // result = {"王五", "张三", "李四"}
1
2
2
尾部追加
aa := [] string{"张三", "李四"}
result := append(aa, "王五", "张飞") // 可以追加多个,result = { "张三", "李四", "王五", "张飞"}
1
2
2
# 删除
删除第i个元素
// 第一种方法(保持剩余元素的次序):
s = append(s[:i], s[i+1:]...)
// 第二种方法(保持剩余元素的次序):
s = s[:i + copy(s[i:], s[i+1:])]
// 上面两种方法都需要复制len(s)-i-1个元素。
// 第三种方法(不保持剩余元素的次序):
s[i] = s[len(s)-1]
s = s[:len(s)-1]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
条件删除:keep判断条件,需要保留的返回true
func filter(data [] *T, keep func(item *T) bool, clear bool) [] *T{
result:=data[:0] // 复用data内存,无需另外开辟。(注:会修改原切片共享数组内容)
for _, d := range data {
if keep(d) {
result = append(result, d)
}
}
if clear { // 避免暂时性的内存泄露。
temp := data[len(result):]
for i := range temp {
temp[i] = nil // t0是类型T的零值
}
}
return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 拷贝
拷贝b切片
方法1
var b [] T
if a!=nil{
b = make([]T, len(a))
copy(b, a)
}
1
2
3
4
5
2
3
4
5
方法2
var b [] T
if a!=nil{
b = append([]T(nil), a...)
}
1
2
3
4
2
3
4
方法3(最简洁)
b = append(a[:0:0], a...)
1
这里就利用了当a为nil的是时候,a[:0:0]并不会报错,仍然会是nil且a[:0:0] == nil为true