围棋中的零检测

我在Go中看到了很多检测nil的代码,像这样:

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

然而,我有一个像这样的结构:

type Config struct {
host string
port float64
}

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

if config == nil {
}

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

256450 次浏览

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

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

config := new(Config) // not nil

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

var config *Config // nil

然后你就能检查是否

if config == nil {
// then
}

除了Oleiade,请参见零值的规格:

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

正如你所看到的,nil并不是所有类型的0值,而是只适用于指针、函数、接口、切片、通道和映射。这就是为什么config == nil是一个错误和

. &config == nil不是 要检查你的结构是否未初始化,你必须检查它的每个成员 各自的零值(例如host == ""port == 0等)或有一个私有字段 由内部初始化方法设置。例子:< / p >
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 }

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

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进行比较,但是它可以检查它是否初始化了。使用这种方法时要小心。如果你的结构可以为它的所有字段都使用零值,你就不会有很多时间。

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

语言规范提到比较操作符的行为:

比较运算符

在任何比较中,第一个操作数必须可赋值给该类型


可分配性

值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 1.13及以后版本中,你可以使用reflect包中提供的Value.IsZero方法。

if reflect.ValueOf(v).IsZero() {
// v is zero, do something
}

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