初始化空切片的正确方法


226

要声明一个具有固定大小的空切片,最好这样做:

mySlice1 := make([]int, 0)

要么:

mySlice2 := []int{}

只想知道哪种方法是正确的。


2
您说的是“非固定大小”,但是切片永远不会有固定大小。除非您的意思是零容量。注意,如果您对可能需要的容量有一个想法/猜测/提示,那么使用三个参数的版本是不错的选择。例如,构建切片地图关键字:keys := make([]int, 0, len(m)); for k, v := range m { keys := append(keys,k) }
Dave C

Answers:


271

您提供的两个选择在语义上是相同的,但是使用make([]int, 0)会导致内部调用runtime.makeslice(Go 1.14)。

您还可以选择保留其nil值:

var myslice []int

Golang.org博客中所述

nil切片在功能上等效于零长度切片,即使它没有指向任何内容。它的长度为零,可以附加分配。

一个nil片段将然而json.Marshal()进入"null"而空片将进入名帅"[]",如通过@farwayer指出。

如@ArmanOrdookhani所指出的,以上选项均不会导致任何分配。



106
请注意:json.Marshal()将返回并返回null已初始化的切片var myslice []int[]myslice := []int{}
远行者

10
另外要注意:reflect.DeepEqual做零片和非空片段之间的区别:a := []int{}var b []intreflect.DeepEqual(a, b) // returns false
asgaines

1
为什么您认为它将进行分配?上限为零,因此未分配任何内容。所有指向零长度事物的指针都指向内存中的相同位置:play.golang.org/p/MPOKKl_sYvw
Arman Ordookhani

1
@ArmanOrdookhani你是正确的。我尝试了一下,并且还发现我对相同的汇编指令的假设是错误的。固定!
阿尼斯(Anisus)

65

它们是等效的。参见以下代码:

mySlice1 := make([]int, 0)
mySlice2 := []int{}
fmt.Println("mySlice1", cap(mySlice1))
fmt.Println("mySlice2", cap(mySlice2))

输出:

mySlice1 0
mySlice2 0

两个切片都具有0容量,这意味着两个切片都具有0长度(不能大于容量),这意味着两个切片都没有元素。这意味着这两个切片在各个方面都是相同的。

看到类似的问题:

在golang中拥有nil slice和empty slice有什么意义?

Go语言中的nil切片vs非nil切片vs空切片


46

作为@ANisus答案的补充...

以下是“行动中”一书中的一些信息,我认为值得一提:

nilempty切片之间的区别

如果我们想到这样的切片:

[pointer] [length] [capacity]

然后:

nil slice:   [nil][0][0]
empty slice: [addr][0][0] // points to an address

无切片

当您要表示不存在的切片时(例如,在返回切片的函数中发生异常时),它们很有用。

// Create a nil slice of integers.
var slice []int

空片

当您要表示一个空集合时,例如当数据库查询返回零结果时,空切片很有用。

// Use make to create an empty slice of integers.
slice := make([]int, 0)

// Use a slice literal to create an empty slice of integers.
slice := []int{}

不管您使用的是零片或空片,内置的功能appendlencap工作一样。


去游乐场的例子

package main

import (
    "fmt"
)

func main() {

    var nil_slice []int
    var empty_slice = []int{}

    fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
    fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))

}

印刷品:

true 0 0
false 0 0

我们可以使用一步来获取空切片的地址make吗?
Simin Jie

如果我们看一下函数签名make似乎不会返回地址。我相信您无法一步一步完成。
tgogos

13

空片和nil片在Go中的初始化方式不同:

var nilSlice []int 
emptySlice1 := make([]int, 0)
emptySlice2 := []int{}

fmt.Println(nilSlice == nil)    // true
fmt.Println(emptySlice1 == nil) // false
fmt.Println(emptySlice2 == nil) // false

至于所有三个切片,len和cap为0。


make([]int, 0)之所以是最好的,是因为Jetbrains GoLand并没有像那样抱怨它是“不必要的” []int{}。这在编写单元测试中很有用。
安德烈·雷曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.