这里的问题是那
shower是一种
interface类型。Go中的接口类型保存实际值及其 动态
类型。关于此的更多详细信息:反射定律#接口的表示。
您返回的切片包含2个非
nil值。第二个值是一个接口值,一个保存
nil指针值的(值;类型)对和一个
*display具体类型。从Go语言规范中引用:比较运算符:
接口值是可比较的。如果两个接口值具有相同的动态类型和相等的动态值,或者两个值都具有value,则它们是相等的
nil。
所以,如果你把它比作
nil,这将是
false。如果将其与代表该对的接口值进行比较
(nil;*display),则将为
true:
if x == (*display)(nil) { panic("everything ok, nil found")}这似乎不可行,因为您必须知道接口所持有的实际类型。但是请注意,您可以使用反射来判断非
nil接口值是否使用来包装
nil值
Value.IsNil()。您可以在Go
Playground上看到一个示例。
为什么以这种方式实施?
与其他具体类型不同的接口(非接口)可以容纳不同具体类型的值(不同的静态类型)。运行时需要知道存储在接口类型变量中的值的动态类型或运行时类型。
An
interface只是一个方法集,如果相同方法属于该类型的方法集的一部分,则
任何类型都可以
实现它。有些类型不能为,例如或为其基础类型的自定义类型。在这些情况下,您将不需要能够存储该特定类型的值。
nil``struct``int``nil
但是 任何类型
还包括
nil有效值(例如切片,地图,通道,所有指针类型)的具体类型,因此,为了在运行时存储满足接口要求的值,可以合理地支持
nil在接口内部进行存储。但是除了
nil接口内部,我们还必须存储其动态类型,因为该
nil值不包含此类信息。
nil当要存储在其中的值是时,替代选项将用作接口值本身
nil,但是此解决方案不足,因为它将丢失动态类型信息。
有人说Go的接口是动态类型的,但这是误导的。它们是静态类型的:接口类型的变量始终具有相同的静态类型,即使在运行时存储在接口变量中的值可能会更改类型,该值也将始终满足接口的要求。
通常,如果要指示类型
nil的值
interface,请使用显式
nil值,然后可以测试是否
nil相等。最常见的示例是内置
error类型,它是一种方法的接口。只要没有错误,就可以显式设置或返回值,
nil而不是某些具体(非接口)类型的错误变量的值(这实际上是错误的做法,请参见下面的演示)。
在您的示例中,混淆源于以下事实:
- 您想要一个值作为接口类型(
shower
) - 但是您要存储在切片中的值不是类型
shower
而是具体类型
因此,当您将一个
*display类型放入
shower切片中时,将创建一个接口值,该接口值是一对(value;
type),其中value是
nil且type是
*display。该对中的 值
将是
nil,而不是接口值本身。如果您将一个
nil值放入分片中,则接口值 本身 为
nil,条件
x == nil为
true。
示范
请参见以下示例:操场
type MyErr stringfunc (m MyErr) Error() string { return "big fail"}func doSomething(i int) error { switch i { default: return nil // This is the trivial true case case 1: var p *MyErr return p // This will be false case 2: return (*MyErr)(nil) // Same as case 1 case 3: var err error // Zero value is nil for the interface return err // This will be true because err is already interface type case 4: var p *MyErr return error(p) // This will be false because the interface points to a // nil item but is not nil itself. }}func main() { for i := 0; i <= 4; i++ { err := doSomething(i) fmt.Println(i, err, err == nil) }}输出:
0 <nil> true1 <nil> false2 <nil> false3 <nil> true4 <nil> false
在情况2
nil中,返回了一个指针,但首先将其转换为接口类型(
error),因此创建了一个接口值,其中包含一个
nil值和该类型
*MyErr,因此该接口值不是
nil。



