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

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

【问题讨论】:

    标签: types interface compiler-errors go


    【解决方案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?

      【讨论】:

      【解决方案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。这避免了为空结构分配内存,就像使用&T{}new(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 是一种静态类型语言。静态类型检查有什么问题?如果不可能进行静态类型检查,那么动态类型检查是合理的,恕我直言。
            • 如果你错过了考试怎么办?
            猜你喜欢
            • 2023-03-14
            • 2011-08-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-11-02
            • 1970-01-01
            • 2012-12-12
            • 2020-10-21
            相关资源
            最近更新 更多