【发布时间】:2012-05-16 22:23:18
【问题描述】:
如何确保类型在编译时实现接口?执行此操作的典型方法是无法从该类型分配支持接口,但是我有几种仅动态转换的类型。在运行时,这会生成非常粗暴的错误消息,而没有为编译时错误提供更好的诊断。在运行时查找我希望支持接口的类型也很不方便,但实际上不支持。
【问题讨论】:
标签: types interface compiler-errors go
如何确保类型在编译时实现接口?执行此操作的典型方法是无法从该类型分配支持接口,但是我有几种仅动态转换的类型。在运行时,这会生成非常粗暴的错误消息,而没有为编译时错误提供更好的诊断。在运行时查找我希望支持接口的类型也很不方便,但实际上不支持。
【问题讨论】:
标签: types interface compiler-errors go
假设问题是关于围棋的,例如
var _ foo.RequiredInterface = myType{} // or &myType{} or [&]myType if scalar
作为 TLD 将在编译时为您检查。
【讨论】:
在 Go 语言中,设计上没有“implements”声明。要求编译器通过尝试赋值来检查类型T 是否实现接口I 的唯一方法(是的,一个虚拟的)。注意,Go 语言区分结构和指针上声明的方法,在赋值检查中使用正确的!
type T struct{}
var _ I = T{} // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.
【讨论】:
通过@smile-on 扩展答案。
在 How can I guarantee my type satisfies an interface? 中,它是 Go 作者的 Frequently Asked Questions (FAQ) 的一部分,声明如下:
您可以要求编译器检查类型
T是否实现了 通过使用T的零值尝试分配来接口I或 指向T的指针,视情况而定。
我们可以用一个例子来说明这一点:
package main
type I interface{ M() }
type T struct{}
func (T) M() {}
//func (*T) M() {} //var _ I = T{}: T does not implement I (M method has pointer receiver)
func main() {
//avoids allocation of memory
var _ I = T{} // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.
//allocation of memory
var _ I = &T{} // Verify that &T implements I.
var _ I = new(T) // Verify that new(T) implements I.
}
如果T(或*T,相应地)没有实现I,错误将在编译时被发现。见Non-interface methods in interface implementation。
如果你不知道它的类型,通常你会检查一个值是否实现了一个接口。如果已知,则检查由编译器自动完成。见Explanation of checking if value implements interface。
空白标识符_ 代表变量名,这里不需要(因此可以防止“已声明但未使用”错误)。 (*T)(nil) 通过将nil 转换为*T,创建了一个指向T 类型值的未初始化指针。见Have trouble understanding a piece of golang code。
这是相同的值,例如,var t *T 在分配任何东西之前所具有的值。见golang interface compliance compile type check。这避免了为空结构分配内存,就像使用&T{} 或new(T) 一样。见Have trouble understanding a piece of golang code。
编辑引用以匹配示例。
【讨论】:
像这样:
http://play.golang.org/p/57Vq0z1hq0
package main
import(
"fmt"
)
type Test int
func(t *Test) SayHello() {
fmt.Println("Hello");
}
type Saluter interface{
SayHello()
SayBye()
}
func main() {
t := Saluter(new(Test))
t.SayHello()
}
将产生:
prog.go:19: cannot convert new(Test) (type *Test) to type Saluter:
*Test does not implement Saluter (missing SayBye method)
【讨论】:
package main
import (
"fmt"
)
type Sayer interface {
Say()
}
type Person struct {
Name string
}
func(this *Person) Say() {
fmt.Println("I am", this.Name)
}
func main() {
person := &Person{"polaris"}
Test(person)
}
func Test(i interface{}) {
//!!here ,judge i implement Sayer
if sayer, ok := i.(Sayer); ok {
sayer.Say()
}
}
【讨论】:
我不喜欢通过在主代码中放置虚拟行来使编译器抛出错误的想法。这是一个可行的智能解决方案,但我更愿意为此目的编写一个测试。
假设我们有:
type Intfc interface { Func() }
type Typ int
func (t Typ) Func() {}
此测试确保Typ 实现Intfc:
package main
import (
"reflect"
"testing"
)
func TestTypes(t *testing.T) {
var interfaces struct {
intfc Intfc
}
var typ Typ
v := reflect.ValueOf(interfaces)
testType(t, reflect.TypeOf(typ), v.Field(0).Type())
}
// testType checks if type t1 implements interface t2
func testType(t *testing.T, t1, t2 reflect.Type) {
if !t1.Implements(t2) {
t.Errorf("%v does not implement %v", t1, t2)
}
}
您可以通过将它们添加到TestTypes 函数来检查所有类型和接口。为 Go 编写测试介绍 here。
【讨论】: