在 Go 语言中,有一种叫做 slice(切片)的类型,它构建于数组之上。当我们想要处理一组数据时,这是一种非常方便的类型。这篇文章将解释 空切片(empty slice)和 nil 切片(nil slice)之间一个微妙但棘手的区别。
一个 nil 切片 是指长度和容量都为零,并且没有底层数组的切片。切片的零值是 nil。如果一个切片像下面这样声明,它就是一个 nil 切片。
package main
import "fmt"
func main() {
var a []string
fmt.Println(a == nil)
}
对于上面的代码片段,输出将是 true 。
一个 空切片 是指长度和容量也为零,但具有长度为零的底层数组的切片。如果一个切片像下面这样声明,它就是一个空切片。
package main
import "fmt"
func main() {
b := []string{}
fmt.Println(b == nil)
}
对于上面的代码片段,输出将是 false 。
也可以使用 make() 函数创建一个空切片。
package main
import "fmt"
func main() {
c := make([]string, 0)
fmt.Println(c == nil)
}
在大多数情况下,空切片和 nil 切片可以被视为相同。只有在一些细微的情况下,它们应该被区别对待,其中之一是在进行 JSON 编码时。
一个空切片在 JSON 中将被编码为 [],而 nil 切片将被编码为 null。
package main
import (
"fmt"
"encoding/json"
)
type A struct {
Data []string
}
func main() {
var a []string
fmt.Println(a == nil)
as := &A{
Data: a,
}
aj, _ := json.Marshal(as)
fmt.Printf("%s\n", string(aj))
b := []string{}
fmt.Println(b == nil)
bs := &A{
Data: b,
}
bj, _ := json.Marshal(bs)
fmt.Printf("%s\n", string(bj))
}
// true
// {"Data":null}
// false
// {"Data":[]}
当这个值作为 API 响应返回时,这将产生很大的差异。前端需要以非常不同的方式对待它。一般来说,nil 切片是一种更受欢迎的风格。