Go中的nil检测

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go中的nil检测相关的知识,希望对你有一定的参考价值。

我在Go中看到很多代码来检测nil,如下所示:

if err != nil { 
    // handle the error    
}

但是,我有一个像这样的结构:

type Config struct {
    host string  
    port float64
}

和config是Config的一个实例,当我这样做时:

if config == nil {
}

有编译错误,说:无法将nil转换为类型Config

答案

编译器将错误指向您,您正在比较结构实例和nil。它们的类型不同,所以它认为它是无效的比较,并对你大喊大叫。

你想要做的是将指向配置实例的指针与nil进行比较,这是一个有效的比较。要做到这一点,你可以使用golang new builtin,或初始化指向它的指针:

config := new(Config) // not nil

要么

config := &Config{
                  host: "myhost.com", 
                  port: 22,
                 } // not nil

要么

var config *Config // nil

然后你就可以检查一下

if config == nil {
    // then
}
另一答案

除了Oleiade,请参阅spec on zero values

当分配内存来存储值时,无论是通过声明还是调用make或new,并且没有提供显式初始化,内存都会被赋予默认初始化。这种值的每个元素都设置为其类型的零值:布尔值为false,整数为0,浮点数为0.0,字符串为“”,指针,函数,接口,切片,通道和映射为nil。这种初始化是递归完成的,因此,例如,如果没有指定值,则结构数组的每个元素都将其字段归零。

如您所见,nil不是每种类型的零值,而是仅用于指针,函数,接口,切片,通道和映射。这就是为什么config == nil是一个错误而&config == nil不是。

要检查您的结构是否未初始化,您必须检查每个成员的相应零值(例如host == ""port == 0等)或具有由内部初始化方法设置的私有字段。例:

type Config struct {
    Host string  
    Port float64
    setup bool
}

func NewConfig(host string, port float64) *Config {
    return &Config{host, port, true}
}

func (c *Config) Initialized() bool { return c != nil && c.setup }
另一答案

我创建了一些示例代码,使用我能想到的各种方法创建新变量。看起来前三种方式创建值,后两种方式创建引用。

package main

import "fmt"

type Config struct {
    host string
    port float64
}

func main() {
    //value
    var c1 Config
    c2 := Config{}
    c3 := *new(Config)

    //reference
    c4 := &Config{}
    c5 := new(Config)

    fmt.Println(&c1 == nil)
    fmt.Println(&c2 == nil)
    fmt.Println(&c3 == nil)
    fmt.Println(c4 == nil)
    fmt.Println(c5 == nil)

    fmt.Println(c1, c2, c3, c4, c5)
}

哪个输出:

false
false
false
false
false
{ 0} { 0} { 0} &{ 0} &{ 0}
另一答案

你也可以像struct_var == (struct{})一样检查。这不允许您与nil进行比较,但它会检查它是否已初始化。使用此方法时要小心。如果您的结构可以为其所有字段都有zero values,那么您将没有多少时间。

package main

import "fmt"

type A struct {
    Name string
}

func main() {
    a := A{"Hello"}
    var b A

    if a == (A{}) {
        fmt.Println("A is empty") // Does not print
    } 

    if b == (A{}) {
        fmt.Println("B is empty") // Prints
    } 
}

http://play.golang.org/p/RXcE06chxE

另一答案

language spec提到比较运营商的行为:

comparison operators

在任何比较中,第一个操作数必须可以分配给第二个操作数的类型,反之亦然。


Assignability

在任何这些情况下,值x都可分配给类型为T的变量(“x可赋予T”):

  • x的类型与T.相同
  • x的类型V和T具有相同的基础类型,并且V或T中的至少一个不是命名类型。
  • T是接口类型,x实现T.
  • x是双向信道值,T是信道类型,x的类型V和T具有相同的元素类型,并且V或T中的至少一个不是命名类型。
  • x是预先声明的标识符nil,T是指针,函数,切片,映射,通道或接口类型。
  • x是一个无类型常量,可由类型T的值表示。

以上是关于Go中的nil检测的主要内容,如果未能解决你的问题,请参考以下文章

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

如何使用模块化代码片段中的LeakCanary检测内存泄漏?

为啥 Go 中的字符串不能为 nil?

Go“一个包含nil指针的接口不是nil接口”踩坑

理解Go语言的nil

使用 Pygments 检测代码片段的编程语言