Go中的零检测
我在Go to detect nil中看到很多代码,如下所示:Go中的零检测,go,null,Go,Null,我在Go to detect nil中看到很多代码,如下所示: if err != nil { // handle the error } type Config struct { host string port float64 } 但是,我有这样一个结构: if err != nil { // handle the error } type Config struct { host string port fl
if err != nil {
// handle the error
}
type Config struct {
host string
port float64
}
但是,我有这样一个结构:
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
或
或
然后你就可以检查一下
if config == nil {
// then
}
除Oleiade外,请参见: 当通过声明或调用make或new分配内存来存储值,并且没有提供显式初始化时,将为内存提供默认初始化此类值的每个元素的类型都设置为零值:布尔值为false,整数为0,浮点值为0.0”,“字符串”为0,指针、函数、接口、切片、通道和映射为nil。此初始化是递归完成的,例如,如果没有指定值,结构数组的每个元素的字段都将为零 正如您所看到的,
nil
不是每种类型的零值,而只是指针、函数、接口、切片、通道和映射的零值。这就是为什么config==nil
是一个错误并且
&config==nil
不是
要检查结构是否未初始化,必须检查每个成员的
相应的零值(例如,主机==”
,端口==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\u 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
}
}
提到比较操作员的行为:
在任何比较中,第一个操作数必须可分配给类型
第二个操作数的值,反之亦然
值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及更高版本中,您可以使用
Value.IsZero
方法,该方法在reflect
包中提供
if reflect.ValueOf(v).IsZero() {
// v is zero, do something
}
除了基本类型外,它还适用于数组、Chan、Func、接口、Map、Ptr、Slice、UnsafePointer和Struct。请参阅以获取参考。进一步了解上述内容,这就是为什么
time.time
有一个IsZero()
方法。但是,如果config==config{}为您检查所有字段,您也可以这样做,如果config==config{}也可以这样做(结构相等在Go中定义得很好)。然而,如果你有很多字段,这是没有效率的。而且,可能零值是一个正常且可用的值,因此传入一个值并不特别。如果以指针形式访问Config,则初始化的函数将失败。可以将其更改为func(c*Config)Initialized()bool{return!(c==nil)}
@Sundar在这种情况下,这样做可能比较方便,因此我应用了更改。但是,通常我不希望方法调用的接收端检查自身是否为nil,因为这应该是调用方的工作。我猜var-config&config//nil
应该是:var-config*config
var-config*config
崩溃,内存地址无效或零指针解引用。也许我们需要var-config-config
我理解这个选择背后的原因可能不是你的,但对我来说,“if!(config!=nil)”是有效的,而“if-config==nil”不是。两者都在同一个结构和非结构之间进行比较。@retorquery它们都无效,请参阅。是否是“!=”或者“==”没有区别;区别在于config是一个结构还是指向结构的指针。我认为这是错误的,因为它总是错误的:我不明白为什么端口是float64类型的?它不应该是。Go的JSON api将任何数字从JSON导入到float64,我必须将float64转换为int。