如何根据下面的变量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为零,但它没有。
答案 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)
nil
是predeclared 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
答案 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)
}