确保在Go语言中在编译时实现一个接口的类型

huangapple go评论85阅读模式
英文:

Ensure a type implements an interface at compile time in Go

问题

我如何确保一个类型在编译时实现了一个接口?通常的做法是通过无法将该类型分配给支持接口来实现,但是我有几种类型只能在动态转换时进行转换。在运行时,这会生成非常粗糙的错误消息,而不是编译时错误提供的更好的诊断信息。在运行时发现我预期支持接口的类型实际上并不支持,这也非常不方便。

英文:

How can I ensure that a type implements an interface at compile time? The typical way to do this is by failure to assign to support interfaces from that type, however I have several types that are only converted dynamically. At runtime this generates very gruff error messages, without the better diagnostics given for compile time errors. It's also very inconvenient to find at run time that types I expected to support interfaces, do in fact not.

答案1

得分: 39

假设问题是关于Go语言的,例如:

var _ foo.RequiredInterface = myType{} // 或 &myType{} 或 [&]myType(如果是标量)

作为一个TLD,它将在编译时为您检查这个问题。

英文:

Assuming the question is about Go, e.g.

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

as a TLD will check that for you at compile time.

答案2

得分: 16

在Go语言中,设计上没有“implements”声明。唯一的方法是通过尝试赋值(是的,一个虚拟的赋值)来要求编译器检查类型T是否实现了接口I。注意,在赋值检查中,Go语言区分在结构体和指针上声明的方法,要使用正确的方法。

type T struct{}
var _ I = T{}       // 验证T是否实现了I。
var _ I = (*T)(nil) // 验证*T是否实现了I。

详细信息请阅读FAQ 为什么Go语言没有“implements”声明?

英文:

In the Go language there is no "implements" declaration by design. The only way to ask the compiler to check that the type T implements the interface I by attempting an assignment (yes, a dummy one). Note, Go lang differentiates methods declared on structure and pointer, use the right one in the assignment check!

type T struct{}
var _ I = T{}       // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.

Read FAQ for details Why doesn't Go have "implements" declarations?

答案3

得分: 13

扩展了@smile-on的答案。

在《如何确保我的类型满足接口?》(https://golang.org/doc/faq#guarantee_satisfies_interface)中,这是Go语言作者的《常见问题(FAQ)》(https://golang.org/doc/faq)的一部分,其中提到:

> 你可以要求编译器使用类型T的零值或指向T的指针进行赋值,以检查类型T是否实现了接口I

我们可以通过以下示例来说明:

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() {
  //避免分配内存
  var _ I = T{}       // 验证 T 是否实现了 I。
  var _ I = (*T)(nil) // 验证 *T 是否实现了 I。
  //分配内存
  var _ I = &T{}      // 验证 &T 是否实现了 I。
  var _ I = new(T)    // 验证 new(T) 是否实现了 I。
}

如果 T(或相应的 *T)没有实现 I,则编译时会捕获到错误。参见 https://stackoverflow.com/questions/51623856/non-interface-methods-in-interface-implementation

通常,如果不知道值的类型,可以检查该值是否实现了接口。如果已知类型,则编译器会自动进行检查。参见 https://stackoverflow.com/questions/27803654/explanation-of-checking-if-value-implements-interface

下划线标识符 _ 代表变量名,在这里不需要使用它(因此避免了“声明但未使用”的错误)。(*T)(nil) 通过将 nil 转换为 *T 来创建一个未初始化的指向 T 类型值的指针。参见 https://stackoverflow.com/questions/30701755/have-trouble-understanding-a-piece-of-golang-code

这与例如 var t *T 在分配任何值之前具有的相同值相同。参见 https://stackoverflow.com/questions/17994519/golang-interface-compliance-compile-type-check。这避免了为空结构体分配内存,就像使用 &T{}new(T) 一样。参见 https://stackoverflow.com/questions/30701755/have-trouble-understanding-a-piece-of-golang-code

引用已编辑以匹配示例。

英文:

Extending the answer by @smile-on.

In How can I guarantee my type satisfies an interface?, which is part of the Frequently Asked Questions (FAQ) by the Go Authors, the following is stated:

> You can ask the compiler to check that the type T implements the
> interface I by attempting an assignment using the zero value for T or
> pointer to T, as appropriate.

We can illustrate this with an example:

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

If T (or *T, accordingly) doesn't implement I, the mistake will be caught at compile time. See https://stackoverflow.com/questions/51623856/non-interface-methods-in-interface-implementation.

Typically you check if a value implements an interface if you don't know its type. If it is known, the check is done by the compiler automatically. See https://stackoverflow.com/questions/27803654/explanation-of-checking-if-value-implements-interface.

The blank identifier _ stands for the variable name, which is not needed here (and thus prevents a "declared but not used" error). (*T)(nil) creates an uninitialized pointer to a value of type T by converting nil to *T. See https://stackoverflow.com/questions/30701755/have-trouble-understanding-a-piece-of-golang-code.

This is the same value which, for example, var t *T has before assigning anything to it. See https://stackoverflow.com/questions/17994519/golang-interface-compliance-compile-type-check. This avoids allocation of memory for an empty struct as you'd get with &T{} or new(T). See https://stackoverflow.com/questions/30701755/have-trouble-understanding-a-piece-of-golang-code.

Quotes edited to match example.

答案4

得分: -3

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()
}
}

英文:
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()
	}
}

The code example is here:http://play.golang.org/p/22bgbYVV6q

答案5

得分: -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检查类型t1是否实现了接口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测试的介绍,请参阅这里

英文:

I don't like the idea of making compiler throw errors by putting dummy lines in the main code. That's a smart solution that works, but I prefer to write a test for this purpose.

Assuming that we have:

type Intfc interface { Func() }
type Typ int
func (t Typ) Func() {}

This test makes sure Typ implements 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)
    }
}

You can check all of your types and interfaces by adding them to TestTypes function. Writing tests for Go is introduced here.

huangapple
  • 本文由 发表于 2012年5月8日 20:23:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/10498547.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定