如何在Golang中检查指向struct net.IPNet的指针的nil值

时间:2017-10-28 00:10:31

标签: go

如何根据下面的变量b赋值来检查零值?

package main

import (
    "fmt"
    "net"
)


type Subnet struct {
    ID                int
    IP                *net.IPNet
}

func main() {
    var s = Subnet{
        ID: 12345,
        IP: &net.IPNet{
            IP:   net.IP{10, 1, 232, 0},
            Mask: net.IPMask{255, 255, 255, 0},
        },
    }
    fmt.Printf("%+v\n", s)
    var b = Subnet{
        ID: 12345,
        IP: &net.IPNet{},
    }
    fmt.Printf("%+v\n", b)
    if b.IP == nil {
        fmt.Println("hello there")
    }
}

这是go playground https://play.golang.org/p/Jk6_3ofyH5

基本上,我希望"你好那里"将打印出来为b.IP为零,但它没有。

4 个答案:

答案 0 :(得分:1)

您似乎将 nil与名为"零值"的概念混淆。

零值

Go中的任何类型 - 无论是标准还是由用户创建 - 有一个零值"这是自动分配给该类型的任何变量的值,否则未明确初始化。 IOW,当你有

type T …

var v T

变量的值" v"将是T类型的零值。

零值的概念自然来自Go的属性 不允许未初始化的变量:Go中的变量总是有 明智的价值观(相反,C)。

nil

一个特殊值nil,它是Go中预先声明的标识符, 是一组具有引用语义的类型的零值。

术语"参考语义"可能是令人生畏的,但也可能是 非常简单地解释:类型在变量时具有引用语义 它引用一些数据结构而不是直接包含它。 因此,当您将此类型的变量的值复制到另一个变量时 变量,两个变量都引用相同的数据结构。

正如您应该知道的,地图,切片,接口和指针在Go中具有引用语义,这就是为什么它们的零值为nil

区别

从上面得出的主要内容是nil是零值 某些类型具有某种属性,但并非所有属性。

例如,

type T struct {
  A int
  B string
}

零值是

T{
  A: 0,
  B: "",
}

即类型T的值,其字段已初始化 到与这些字段的类型对应的零值: 0为int和"" string

您的特定问题

在您的类型中

type Subnet struct {
    ID                int
    IP                *net.IPNet
}

领域" IP"有一个指针类型*net.IPNet,它是一个指针 到net.IPNet类型的值。 因此,其零值为nil

现在,如果您要声明类似

的内容
var subnet Subnet

这个变量会将其生命初始化为零值 它的类型,这意味着它的领域" IP" 它的类型nil将为零值。

在您的示例中,您执行:

var b = Subnet{
    ID: 12345,
    IP: &net.IPNet{},
}

这意味着创建一个变量" b"初始化为特定的 由放置在右侧的文字定义的值 赋值运算符=

领域" IP"在该文字中初始化为零值 其类型;相反,它被初始化为包含该指针的指针 匿名变量的地址 wihch的类型为net.IPNet 并包含该类型的零值。

用不同的话来说,结果大致相当 以下内容:

var ip net.IPNet

var b = Subnet{
    ID: 12345,
    IP: &ip,
}

那里,变量" ip"包含其类型的零值, 和变量" b.IP"包含指向变量的指针" ip"。

自那个领域" IP"指向一些真实的内存位置, 它的值显然不是nil,它使得类型的值具有 refence semantics"指向无处", 这就是为什么if语句中的测试失败的原因。

答案 1 :(得分:0)

支票应该是,      if b.IP != nil { fmt.Println("hello there") } 输出将有hello-world,

{ID:12345 IP:10.1.232.0/24} {ID:12345 IP:} 你好吗

注意:Golang的nil与Cpp的NULL不同,它是相反的。

答案 2 :(得分:0)

Go中的{p> nilpredeclared identifier。例如,

package main

import (
    "fmt"
    "net"
)

type Subnet struct {
    ID int
    IP *net.IPNet
}

func main() {
    var b = Subnet{ID: 1, IP: nil}
    fmt.Println(b.IP == nil)
}

输出:

true

游乐场:https://play.golang.org/p/-745-hhLGg

答案 3 :(得分:0)

请注意,inputNumber = 20 x = currentMultiplicand = 1 targetValue = 40 lr = 0.001 #first step (x=1): mse = (40-20x)² = 400 gradient = -2*(40-20x)*20 = -800 update = - lr * gradient = 0.8 new x = 1.8 #second step (x=1.8): mse = (40-20x)² = 16 #(now this is better) gradient = -2*(40-20x)*20 = -160 update = - lr * gradient = 0.16 #(decreasing update sizes....) new x = 1.96 #you can see from here that this converging... 具有 String() string函数,这使其实现Stringer interface。基本上,此函数在打印结构时提供结构的自定义字符串表示。如果您进一步深入the source code,当IPNet"<nil>"为零时,您会看到此函数返回字符串IPNet.IP。这解释了当IPNet.Mask字段的值实际上不是<nil>时,代码如何打印Subnet.IP

现在,从字面上回答标题中的问题,您已经通过将值与nil进行比较来正确地进行了检查。此外,您可以尝试使用nil进行打印,例如:

%#v

<强> playground

输出

func main() {
    var b = Subnet{ID: 12345, IP: &net.IPNet{}}
    fmt.Printf("%#v\n", b)
    fmt.Printf("is null: %t\n", b.IP == nil)
    var c = Subnet{ID: 12345, IP: nil}
    fmt.Printf("%#v\n", c)
    fmt.Printf("is null: %t", c.IP == nil)
}