Go语言 声明切片还是生成切片?

z8dt9xmd  于 2023-09-28  发布在  Go
关注(0)|答案(5)|浏览(95)

在Go语言中,var s []ints := make([]int, 0)有什么区别?
我觉得这两种都可以,但哪一种更好呢?

niwlg2el

niwlg2el1#

简单声明

var s []int

不分配内存,s指向nil,而

s := make([]int, 0)

分配内存,s将内存指向具有0个元素的片。
通常,如果您不知道用例的确切大小,那么第一个更符合习惯。

syqv5f0l

syqv5f0l2#

除了fabriziomanswer,你可以在“Go Slices: usage and internals“中看到更多的例子,其中提到了[]int的用途:
由于slice的零值(nil)的作用类似于零长度slice,因此可以声明一个slice变量,然后在循环中附加到它:

// Filter returns a new slice holding only
// the elements of s that satisfy f()
func Filter(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

这意味着,要追加到切片,您不必首先分配内存:nilp int[]足以作为要添加的片。

i2loujxw

i2loujxw3#

只是发现了不同。如果使用

var list []MyObjects

然后将输出编码为JSON,得到null

list := make([]MyObjects, 0)

结果为[]

mutmk8jj

mutmk8jj4#

一个更完整的例子(.make()中还有一个参数):

slice := make([]int, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

输出:

length:  2 - capacity 5 - content:  [0 0]

或者使用动态类型slice

slice := make([]interface{}, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

输出:

length:  2 - capacity 5 - content:  [<nil> <nil>]
xlpyo6sf

xlpyo6sf5#

Slice可能会超出其容量,这意味着内存重新分配,这可能是昂贵的(需要一些时间)。有一个关于切片如何增长的规则:
Go切片的大小增加一倍,直到1024,之后每次增加25
现在让我们比较两种方法:

  • var p []int
  • p := make([]int, 0, len(s))

下面我们有两个函数,一个只声明切片,另一个使用make创建切片并设置其容量。

func FilterSliceNil(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

func FilterSliceCapSet(s []int, fn func(int) bool) []int {
    p := make([]int, 0, len(s)) // Set length=0 and capacity to length of s
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

基准测试功能:

package main

import (
    "testing"
)

var slice = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var f = func(i int) bool {
    return i%2 == 0
}

func Benchmark_FilterSliceNil(b *testing.B) {
    for i := 0; i < b.N; i++ {
        FilterSliceNil(slice, f)
    }
}

func Benchmark_FilterSliceCapSet(b *testing.B) {
    for i := 0; i < b.N; i++ {
        FilterSliceCapSet(slice, f)
    }
}

基准测试结果:

$ go test -bench=. -benchtime=10s
goos: linux
goarch: amd64
pkg: example.com/Shadowing
cpu: 13th Gen Intel(R) Core(TM) i7-13700K
Benchmark_FilterSliceNil-24             157664690               76.96 ns/op
Benchmark_FilterSliceCapSet-24          330690351               36.27 ns/op
PASS
ok      example.com/Filter   35.479s

在我的机器上,使用make的版本需要一半的时间才能完成。

相关问题