GO外文翻译计划golang.org/doc/effecti…
接口的类型不必显式声明它实现了接口。 相反,类型仅通过实现接口的方法来实现接口。 实际上,大多数接口转换都是静态的,因此在编译时进行检查。 例如,将* os.File传递给期望io.Reader的函数将不会编译,除非* os.File实现io.Reader接口。
但是,某些接口检查的确在运行时进行。 编码/ json包中有一个实例,它定义了Marshaler接口。 当JSON编码器收到实现该接口的值时,编码器将调用该值的编组方法将其转换为JSON,而不是执行标准转换。 编码器在运行时使用类型声明来检查此属性,例如:
m, ok := val.(json.Marshaler)
如果只需要询问某个类型是否实现了一个接口,而没有实际使用该接口本身(也许作为错误检查的一部分),则可以使用空白标识符忽略类型声明的值:
if _, ok := val.(json.Marshaler); ok {
fmt.Printf("value %v of type %T implements json.Marshaler\n", val, val)
}
出现这种情况的一个地方是,有必要在实现该类型的包中保证它实际上满足接口的情况。 如果某个类型(例如json.RawMessage)需要自定义JSON表示形式,则应实现json.Marshaler,但是没有静态转换会导致编译器自动对此进行验证。 如果类型意外地不满足该接口,则JSON编码器仍将起作用,但将不使用自定义实现。 为了确保实现正确,可以在包中使用使用空白标识符的全局声明:
var _ json.Marshaler = (*RawMessage)(nil)
在此声明中,涉及将* RawMessage转换为Marshaler的赋值要求* RawMessage实现Marshaler,并且将在编译时检查该属性。 如果json.Marshaler接口发生更改,则此软件包将不再编译,我们会注意到需要对其进行更新。
在此构造中出现空白标识符表示该声明仅存在于类型检查中,而不用于创建变量。 但是,请不要对满足接口的每种类型都执行此操作。 按照惯例,只有在代码中不存在静态转换的情况下才使用此类声明,这是罕见的事件。