go语言 Slice 三种声明方式比较

橙子1001 2019-01-21 12:32:43
//方式一 make([]type,len,cap)

slice1 := make([]int, 0, 9)
for i := 0; i < 9; i++ {
slice1 = append(slice1, i)
}


//方式二 make([]type,cap)
slice2 := make([]int, 9)
for i := 0; i < 9; i++ {
slice2[i] = i
}

//方式三 var xxx []type
var slice3 []int
for i := 0; i < 9; i++ {
slice3 = append(slice3, i)
}

结论:

方式一,在初始化时,申请cap大小的数组空间,每添加一个元素,len会变长,cap不变,适应于使用前已知slice长度的情况

方式二,在初始化时,申请cap大小的数组空间,每添加一个元素,len和cap都不变,适应于使用前已知slice长度的情况,(注意:方式二不能用append,否则append的数据,不会从第一个元素开始添加,而是会添加到slice的最末尾)

方式三,在初使化时,申请空间为0,根据使用情况动态扩充空间大小, 每添加一个元素,len和cap都会变 ,适应于使用前未知数组长度的情况

性能:方式一和方式二差不多,方式三,性能较差。


相关测试代码

slice__test.go 代码


package main

import (
"testing"
)

func TestSliceLenCap(t *testing.T) {
slice1 := make([]int, 0, 9)
t.Log("方式一:")
t.Log("slice1 := make([]int, 0, 9)")
t.Log("slice1 = append(slice1, i)")
for i := 0; i < 9; i++ {
slice1 = append(slice1, i)
t.Log("slice1 len=", len(slice1), " ,cap=", cap(slice1))
}
t.Log(slice1)
}

func TestSliceCap(t *testing.T) {
slice2 := make([]int, 9)
t.Log("方式二:")
t.Log("slice2 := make([]int, 9)")
t.Log("slice2[i] = i")
for i := 0; i < 9; i++ {
slice2[i] = i
t.Log("slice2 len=", len(slice2), " ,cap=", cap(slice2))
}
t.Log(slice2)
}

func TestSliceVar(t *testing.T) {
var slice3 []int
t.Log("方式三:")
t.Log("var slice3 []int")
t.Log("slice3 = append(slice3, i)")
for i := 0; i < 9; i++ {
slice3 = append(slice3, i)
t.Log("slice3 len=", len(slice3), " ,cap=", cap(slice3))
}
t.Log(slice3)
}




首先做一下 go test查看输出的len 和cap
go test -v

结果:
[root@JD gtestSlice]# go test -v
=== RUN TestSliceLenCap
--- PASS: TestSliceLenCap (0.00s)
main_test.go:9: 方式一:
main_test.go:10: slice1 := make([]int, 0, 9)
main_test.go:11: slice1 = append(slice1, i)
main_test.go:14: slice1 len= 1 ,cap= 9
main_test.go:14: slice1 len= 2 ,cap= 9
main_test.go:14: slice1 len= 3 ,cap= 9
main_test.go:14: slice1 len= 4 ,cap= 9
main_test.go:14: slice1 len= 5 ,cap= 9
main_test.go:14: slice1 len= 6 ,cap= 9
main_test.go:14: slice1 len= 7 ,cap= 9
main_test.go:14: slice1 len= 8 ,cap= 9
main_test.go:14: slice1 len= 9 ,cap= 9
main_test.go:16: [0 1 2 3 4 5 6 7 8]
=== RUN TestSliceCap
--- PASS: TestSliceCap (0.00s)
main_test.go:21: 方式二:
main_test.go:22: slice2 := make([]int, 9)
main_test.go:23: slice2[i] = i
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:26: slice2 len= 9 ,cap= 9
main_test.go:28: [0 1 2 3 4 5 6 7 8]
=== RUN TestSliceVar
--- PASS: TestSliceVar (0.00s)
main_test.go:33: 方式三:
main_test.go:34: var slice3 []int
main_test.go:35: slice3 = append(slice3, i)
main_test.go:38: slice3 len= 1 ,cap= 1
main_test.go:38: slice3 len= 2 ,cap= 2
main_test.go:38: slice3 len= 3 ,cap= 4
main_test.go:38: slice3 len= 4 ,cap= 4
main_test.go:38: slice3 len= 5 ,cap= 8
main_test.go:38: slice3 len= 6 ,cap= 8
main_test.go:38: slice3 len= 7 ,cap= 8
main_test.go:38: slice3 len= 8 ,cap= 8
main_test.go:38: slice3 len= 9 ,cap= 16
main_test.go:40: [0 1 2 3 4 5 6 7 8]
PASS
ok _/home/code/study_go_code/slice_len_cap/gtestSlice 0.002s



然后用go test 的基准测试测试一下性能对比:

slice_benchmark_test.go 代码:


package main

import (
"testing"
)

var (
num = 2
)

func BenchmarkSliceLenCap(b *testing.B) {
slice1 := make([]int, 0, b.N/num)
b.ResetTimer()
for i := 0; i < b.N/num; i++ {
slice1 = append(slice1, i)
}
}

func BenchmarkSliceCap(b *testing.B) {
slice2 := make([]int, b.N/num)
b.ResetTimer()
for i := 0; i < b.N/num; i++ {
slice2[i] = i
}
}
func BenchmarkSliceVar(b *testing.B) {
var slice3 []int
b.ResetTimer()
for i := 0; i < b.N/num; i++ {
slice3 = append(slice3, i)
}
}



执行基准测试命令,

结果 :

go test -bench=. -run=none

goos: linux
goarch: amd64
BenchmarkSliceLenCap-2 200000000 6.15 ns/op
BenchmarkSliceCap-2 200000000 6.29 ns/op
BenchmarkSliceVar-2 100000000 10.6 ns/op
PASS
ok _/home/code/study_go_code/slice_len_cap/gbenchmark 5.668s















































...全文
300 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
王桑的一天 2019-03-06
  • 打赏
  • 举报
回复
各有应用场合。方式三适合存放数据库检索结果
szqh97 2019-03-05
  • 打赏
  • 举报
回复
楼主可以再去看下slice的源码实现,结合测试,印象主就更深了
可爱的小莱 2019-01-22
  • 打赏
  • 举报
回复
有意思吗,搞这些测试。
王桑的一天 2019-01-21
  • 打赏
  • 举报
回复
因为方式三要不断的扩容重新分配空间吧

2,190

社区成员

发帖
与我相关
我的任务
社区描述
go语言学习与交流版
社区管理员
  • go语言社区
  • Freeman Z
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧