我在Go中看到很多代码来检测nil,如下所示:
if err != nil {
// handle the error
}
但是,我有一个像这样的结构:
type Config struct {
host string
port float64
}
和config是Config的一个实例,当我这样做时:
if config == nil {
}
有编译错误,说: 无法将nil转换为类型Config
答案 0 :(得分:153)
编译器将错误指向您,您正在比较结构实例和nil。它们的类型不同,所以它认为它是无效的比较,并对你大喊大叫。
这里你要做的是将指向配置实例的指针与nil进行比较,这是一个有效的比较。要做到这一点,你可以使用golang new 内置,或初始化指向它的指针:
config := new(Config) // not nil
或
config := &Config{
host: "myhost.com",
port: 22,
} // not nil
或
var config *Config // nil
然后你就可以检查是否
if config == nil {
// then
}
答案 1 :(得分:54)
除了Oleiade,请参阅spec on zero values:
当分配内存来存储值时,无论是通过声明还是调用make或new,并且没有提供显式初始化,内存都会被赋予默认初始化。 此类值的每个元素都设置为其类型的零值:布尔值为false,整数为0,浮点数为0.0,字符串为“”,指针,函数,接口,切片,通道和nil为nil map。这个初始化是递归完成的,所以例如,如果没有指定值,结构数组的每个元素都会将其字段归零。
如您所见,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 }
答案 2 :(得分: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)
}
输出:
false
false
false
false
false
{ 0} { 0} { 0} &{ 0} &{ 0}
答案 3 :(得分:6)
您也可以查看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
}
}
答案 4 :(得分:3)
language spec提及比较运营商'行为:
在任何比较中,第一个操作数必须可分配给该类型 第二个操作数,或反之亦然。
值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的值表示。
答案 5 :(得分:2)
在Go 1.13和更高版本中,您可以使用Value.IsZero
软件包中提供的reflect
方法。
if reflect.ValueOf(v).IsZero() {
// v is zero, do something
}
除基本类型外,它还适用于Array,Chan,Func,Interface,Map,Ptr,Slice,UnsafePointer和Struct。请参阅this以供参考。