go语言的切片研究
温馨提示:
本文最后更新于 2022年03月31日,已超过 923 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我。
切片slice
Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
声明切片
package main
import "fmt"
func main() {
//1:direct declare variable
var s1 []int
//s1 = []int{}
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
//2:assignment variable
s2 := []int{1,2,3}
fmt.Printf("s2: %v,len: %v,cap: %v \n",s2,len(s2),cap(s2))
//3:make slice
s3 :=make([]int,0)
fmt.Printf("s3 %v,len: %v,cap: %v \n",s3,len(s3),cap(s3))
//3:make slice and assignment slice length
s4 :=make([]int,0,10)
fmt.Printf("s4: %v,len: %v,cap: %v \n",s4,len(s4),cap(s4))
//4:slice by array
arr := [5]int{1,2,3,4,5}
s5 := arr[:]
fmt.Printf("s5: %v,len: %v,cap: %v \n",s5,len(s5),cap(s5))
s6 := arr[1:len(arr)-1]
fmt.Printf("s6: %v,len: %v,cap: %v \n",s6,len(s6),cap(s6))
//5:slice by slice
s7 := []int{1,2,3,4,5,6,7,8,9,10}
fmt.Printf("s7: %v,len: %v,cap: %v \n",s7,len(s7),cap(s7))
s8 := s7[1:len(arr)-1]
fmt.Printf("s8: %v,len: %v,cap: %v \n",s8,len(s8),cap(s8))
//[x:y:z] x:start index y:end index z:slice cap=z-x
s9 := s7[6:10:10]
fmt.Printf("s9: %v,len: %v,cap: %v \n",s9,len(s9),cap(s9))
}
切片cap,len
cap
切片容量,在追加切片时,可能会使得切片容量变大
len
切片长度,表示切片数组的长度
package main
import "fmt"
func main() {
var s1 []int
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
s1 = []int{1,2,3}
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
var arr =[]int{1,2,3,4,5,6,7,8,9,10}
s2 := arr[0:5]
fmt.Printf("s2: %v,len: %v,cap: %v \n",s2,len(s2),cap(s2))
}
输出:
可以看到,在数组中获取切片后,cap=10,len=5
切片的cap永远是大于等于len的
空nil切片
切片未初始化之前,切片等于nil,len和cap都为0
操作切片
append 切片追加数据
package main
import (
"fmt"
)
func main() {
var s1 = make([]int,0,10)
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
s1 = append(s1,1,2,3,4 )
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
}
当追加的数据超出cap容量时,将会触发切片重新分配底层数组,即时原数组并未被填满
重新分配底层数组时,一般以原有cap进行二倍扩容分配
package main
import (
"fmt"
)
func main() {
var s1 = make([]int,0,4)
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
s1 = append(s1,1,2,3,4)
fmt.Printf("1 s1 pointer: %p \n",s1)
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
fmt.Printf("2 s1 pointer: %p \n",s1)
s1 = append(s1,5,6)
fmt.Printf("s1: %v,len: %v,cap: %v \n",s1,len(s1),cap(s1))
fmt.Printf("3 s1 pointer: %p \n",s1)
}
注意:由于每次超出时都会重新分配数组,在开发时应该避免重新分配,一次性定义好切片的容量
copy
copy函数可以将一个切片的元素复制到另一个切片,复制的长度由最小的切片长度为准:
package main
import (
"fmt"
)
func main() {
var s1 = make([]int, 0, 4)
var s2 = make([]int, 0, 10)
s1 = append(s1, 9)
s2 = append(s2, 1, 2, 3, 4, 5, 6)
copy(s2,s1)
fmt.Printf("s1: %v,len: %v,cap: %v \n", s1, len(s1), cap(s1))
fmt.Printf("s2: %v,len: %v,cap: %v \n", s2, len(s2), cap(s2))
}
输出:
s1: [9],len: 1,cap: 4
s2: [9 2 3 4 5 6],len: 6,cap: 10
当s1复制到s2时,s1的元素将完全复制到s2中(如果s2容量比s1长度小,则会忽略s1超出的部分)
切片copy自身
当切片 通过[:x]方式创建新切片时,将直接使用原有切片的地址,同时如果新切片发生了更改,原有切片也将发生更改:
package main
import (
"fmt"
)
func main() {
s1 :=[]int{1,2,3,4,5,6,7,8,9}
s2 :=s1[8:]
s3 :=s1[:8]
fmt.Printf("s1 pointer:%p \n", s1)
fmt.Printf("s2 pointer:%p \n", s2)
fmt.Printf("s3 pointer:%p \n", s3)
//s2 pointer == s3 pointer
copy(s3,s2)
fmt.Printf("s3: %v,len: %v,cap: %v \n", s3, len(s3), cap(s3))
fmt.Printf("s1: %v,len: %v,cap: %v \n", s1, len(s1), cap(s1))
}
输出:
s1 pointer:0xc00001e0a0
s2 pointer:0xc00001e0e0
s3 pointer:0xc00001e0a0
s3: [9 2 3 4 5 6 7 8],len: 8,cap: 9
s1: [9 2 3 4 5 6 7 8 9],len: 9,cap: 9
切片遍历
可直接通过range遍历:
package main
import (
"fmt"
)
func main() {
s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Printf("s1: %v,len: %v,cap: %v \n", s1, len(s1), cap(s1))
for key, value := range s1 {
fmt.Printf("key:%v,value:%v \n",key,value)
}
}
正文到此结束
- 本文标签: 编程语言
- 本文链接: https://www.php20.cn/article/356
- 版权声明: 本文由仙士可原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权