Go中的nil检测

Qia*_*hen 144 null go

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

if err != nil { 
    // handle the error    
}
Run Code Online (Sandbox Code Playgroud)

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

type Config struct {
    host string  
    port float64
}
Run Code Online (Sandbox Code Playgroud)

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

if config == nil {
}
Run Code Online (Sandbox Code Playgroud)

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

Ole*_*ade 167

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

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

config := new(Config) // not nil
Run Code Online (Sandbox Code Playgroud)

要么

config := &Config{
                  host: "myhost.com", 
                  port: 22,
                 } // not nil
Run Code Online (Sandbox Code Playgroud)

要么

var config *Config // nil
Run Code Online (Sandbox Code Playgroud)

然后你就可以检查一下

if config == nil {
    // then
}
Run Code Online (Sandbox Code Playgroud)

  • 我猜`var config&Config // nil`应该是:`var config*Config` (5认同)

nem*_*emo 57

除Oleiade外,请参阅零值规范:

当分配内存来存储值时,无论是通过声明还是调用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 }
Run Code Online (Sandbox Code Playgroud)

  • 除此之外,这就是为什么`time.Time`有一个`IsZero()`方法.但是你也可以做[`var t1 time.Time; 如果t1 == time.Time {}`](https://play.golang.org/p/n7EfFVlzrB),你*也可以*如果config == Config {}`来检查所有字段(结构相等在Go中得到很好的定义.但是,如果你有很多字段,那就没有效率了.并且,也许零值是一个理智且可用的值,因此传入一个并不特殊. (4认同)

Qia*_*hen 16

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

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)
}
Run Code Online (Sandbox Code Playgroud)

哪个输出:

false
false
false
false
false
{ 0} { 0} { 0} &{ 0} &{ 0}
Run Code Online (Sandbox Code Playgroud)


The*_*ist 6

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

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
    } 
}
Run Code Online (Sandbox Code Playgroud)

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


mrp*_*dey 5

在 Go 1.13 及更高版本中,您可以使用包中Value.IsZero提供的方法reflect

if reflect.ValueOf(v).IsZero() {
    // v is zero, do something
}
Run Code Online (Sandbox Code Playgroud)

除了基本类型,它还适用于 Array、Chan、Func、Interface、Map、Ptr、Slice、UnsafePointer 和 Struct。请参阅以供参考。