【问题标题】:Correct way to initialize empty slice初始化空切片的正确方法
【发布时间】:2015-05-23 17:38:40
【问题描述】:

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

mySlice1 := make([]int, 0)

或:

mySlice2 := []int{}

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

【问题讨论】:

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

标签: arrays go slice


【解决方案1】:

您提供的两个替代方案在语义上是相同的,但使用 make([]int, 0) 将导致对 runtime.makeslice 的内部调用(Go 1.16)。

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

var myslice []int

Golang.org blog中所写:

nil 切片在功能上等同于零长度切片,即使它不指向任何内容。它的长度为零,可以通过分配附加到。

正如@farwayer 所指出的,nil 切片将 json.Marshal() 转换为 "null",而空切片将编组为 "[]"

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

【讨论】:

  • 也在维基上提到github.com/golang/go/wiki/…
  • 小心:json.Marshal() 将返回 null 用于 var myslice []int[] 用于初始化切片 myslice := []int{}
  • 还要小心:reflect.DeepEqual 区分零切片和非零切片:a := []int{},var b []int,reflect.DeepEqual(a, b) // returns false
  • 为什么你认为它会做分配?上限为零,因此没有分配任何内容。所有指向零长度事物的指针都指向内存中的相同位置:play.golang.org/p/MPOKKl_sYvw
  • @ArmanOrdookhani 你是对的。我试过了,我还发现我对相同组装说明的假设是错误的。固定!
【解决方案2】:

它们是等价的。请参阅此代码:

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

输出:

mySlice1 0
mySlice2 0

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

查看类似问题:

What is the point of having nil slice and empty slice in golang?

nil slices vs non-nil slices vs empty slices in Go language

【讨论】:

    【解决方案3】:

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

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

    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{}
    

    无论您使用的是 nil 切片还是空切片,内置函数 appendlencap 的工作原理都是一样的。


    Go playground example:

    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可以一步获取空切片的地址吗?
    • 如果我们看一下函数signaturemake 似乎没有返回地址。我相信你不可能一步到位。
    【解决方案4】:

    空切片和空切片在 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{} 那样抱怨它是“不必要的”。这在编写单元测试时很有用。
    【解决方案5】:

    除了@ANisus 的回答

    当使用官方的Go MongoDb Driver 时,nil 切片也将编组为"null",而空切片将编组为"[]"

    使用社区支持的MGO driver 时,nil 和空切片都将编组到"[]"

    参考:https://jira.mongodb.org/browse/GODRIVER-971

    【讨论】:

      猜你喜欢
      • 2017-01-22
      • 2019-10-24
      • 2019-10-03
      • 2017-11-19
      • 2018-01-13
      • 2018-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多