确保类型在 Go 编译时实现接口

Posted

技术标签:

【中文标题】确保类型在 Go 编译时实现接口【英文标题】:Ensure a type implements an interface at compile time in Go 【发布时间】:2012-05-16 22:23:18 【问题描述】:

如何确保类型在编译时实现接口?执行此操作的典型方法是无法从该类型分配支持接口,但是我有几种仅动态转换的类型。在运行时,这会生成非常粗暴的错误消息,而没有为编译时错误提供更好的诊断。在运行时查找我希望支持接口的类型也很不方便,但实际上不支持。

【问题讨论】:

【参考方案1】:

假设问题是关于围棋的,例如

var _ foo.RequiredInterface = myType // or &myType or [&]myType if scalar

作为 TLD 将在编译时为您检查。

【讨论】:

【参考方案2】:

在 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.

详情请阅读常见问题解答Why doesn't Go have "implements" declarations?

【讨论】:

http://play.golang.org/p/UNXt7MlmX8 强调指针和结构赋值检查的区别【参考方案3】:

通过@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。这避免了为空结构分配内存,就像使用&Tnew(T) 一样。见Have trouble understanding a piece of golang code。

编辑引用以匹配示例。

【讨论】:

【参考方案4】:

像这样:

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)

【讨论】:

【参考方案5】:
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()
    

代码示例在这里:http://play.golang.org/p/22bgbYVV6q

【讨论】:

【参考方案6】:

我不喜欢通过在主代码中放置虚拟行来使编译器抛出错误的想法。这是一个可行的智能解决方案,但我更愿意为此目的编写一个测试。

假设我们有:

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。

【讨论】:

呃,不。 IMO 不建议使用反射编写测试用例来避免编译器的静态类型检查。 Go 是一种静态类型语言。静态类型检查有什么问题?如果不可能进行静态类型检查,那么动态类型检查是合理的,恕我直言。 如果你错过了考试怎么办?

以上是关于确保类型在 Go 编译时实现接口的主要内容,如果未能解决你的问题,请参考以下文章

Golang内部构件,第2部分:深入Go编译器

19.go语言基础学习(上)——2019年12月16日

go——结构体

[翻译]Go与C#对比 第三篇:编译运行时类型系统模块和其它的一切

[翻译]Go与C#对比 第三篇:编译运行时类型系统模块和其它的一切

[翻译]Go与C#对比 第三篇:编译运行时类型系统模块和其它的一切