检查变量是否实现了接口而不进行编译。

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

Checking of variable implements interface without compiling

问题

我想知道一个具体类型是否实现了特定的接口,并将其打印出来。
我已经写了一个示例[0],其中定义了一个自定义的结构体(MyPoint),它不是一个接口类型。MyPoint具有在io.Reader接口中定义的Read函数:

  1. type MyPoint struct {
  2. X, Y int
  3. }
  4. func (pnt *MyPoint) Read(p []byte) (n int, err error) {
  5. return 42, nil
  6. }

目标是获取具体类型p是否实现了io.Writer接口的信息。
因此,我写了一个简短的main函数来进行检查,希望能得到一个true的结果。

  1. func main() {
  2. p := MyPoint{1, 2}
  3. }

最初的想法是使用反射和类型断言来检查,将check(p)添加到main函数中。

  1. func checkType(tst interface{}) {
  2. switch tst.(type) {
  3. case nil:
  4. fmt.Printf("nil")
  5. case *io.Reader:
  6. fmt.Printf("p is of type io.Reader\n")
  7. case MyPoint:
  8. fmt.Printf("p is of type MyPoint\n")
  9. default:
  10. fmt.Println("p is unknown.")
  11. }
  12. }

输出结果是:p is of type MyPoint。经过一些研究,我知道我应该预料到这个结果,因为Go的类型是静态的,所以p的类型是MyPoint,而不是io.Reader。此外,io.Reader是一个接口类型,与MyPoint类型不同。

我在[1]找到了一个解决方案,它在编译时检查MyPoint是否可以是io.Reader。它是有效的。

  1. var _ io.Reader = (*MyPoint)(nil)

但这不是我想要的解决方案。类似下面的尝试也失败了。我认为这是因为上述原因,对吗?

  1. i := interface{}(new(MyPoint))
  2. if _, ok := i.(io.Reader); ok {
  3. fmt.Println("i is an io.Reader")
  4. }
  5. pType := reflect.TypeOf(p)
  6. if _, ok := pType.(io.Reader); ok {
  7. fmt.Println("The type of p is compatible to io.Reader")
  8. }
  9. readerType := reflect.TypeOf((*io.Reader)(nil)).Elem()
  10. fmt.Printf("p impl. Reader %t \n", pType.Implements(readerType))

是否存在一种在不编译的情况下检查p是否实现了该接口的解决方案?我希望有人能帮助我。

[0] http://play.golang.org/p/JCsFf7y74C(已修复)
http://play.golang.org/p/cIStOOI84Y(旧版)

[1] https://stackoverflow.com/questions/27803654/explanation-of-checking-if-value-implements-interface-golang

英文:

I want to know whether a concrete type implements a specefic interface and print it out.
I have written an example [0] with a self defined struct (MyPoint) beeing not an interface-type. MyPoint has the function Read as defined in the interface of io.Reader:

  1. type MyPoint struct {
  2. X, Y int
  3. }
  4. func (pnt *MyPoint) Read(p []byte) (n int, err error) {
  5. return 42, nil
  6. }

The aim is to get the information that the concrete type p implements the interface io.Writer.
Therefore I have written a short main trieng to get a true for the check.

  1. func main() {
  2. p := MyPoint{1, 2}
  3. }

The first idea was to check it with the help of reflection and a type-switch and adding check(p) to to the main-function.

  1. func checkType(tst interface{}) {
  2. switch tst.(type) {
  3. case nil:
  4. fmt.Printf("nil")
  5. case *io.Reader:
  6. fmt.Printf("p is of type io.Reader\n")
  7. case MyPoint:
  8. fmt.Printf("p is of type MyPoint\n")
  9. default:
  10. fmt.Println("p is unknown.")
  11. }
  12. }

The output is: p is of type MyPoint. After a bit of research I know that I should have expected that because Go's types are static and therefore the type of p is MyPoint and not io.Reader. In addition to that io.Reader is an interface-type which is different to type MyPoint.

I found one solution e.g. at [1] which checks whether MyPoint can be an io.Reader at compile time. It works.

  1. var _ io.Reader = (*MyPoint)(nil)

But that isn't the solution I wanted. Tries like below fails, too. I think it's because of the reason above, isn't it?

  1. i := interface{}(new(MyPoint))
  2. if _, ok := i.(io.Reader); ok {
  3. fmt.Println("i is an io.Reader")
  4. }
  5. pType := reflect.TypeOf(p)
  6. if _, ok := pType.(io.Reader); ok {
  7. fmt.Println("The type of p is compatible to io.Reader")
  8. }
  9. readerType := reflect.TypeOf((*io.Reader)(nil)).Elem()
  10. fmt.Printf("p impl. Reader %t \n", pType.Implements(readerType))

Exists one solution to check whether p implements the interface without compiling? I hope that someone can help me.

[0] http://play.golang.org/p/JCsFf7y74C (fixed)
http://play.golang.org/p/cIStOOI84Y (old)

[1] https://stackoverflow.com/questions/27803654/explanation-of-checking-if-value-implements-interface-golang

答案1

得分: 8

你想要的功能完全可以使用reflect包来实现。以下是一个示例:

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "reflect"
  6. )
  7. type Other int
  8. type MyPoint struct {
  9. X, Y int
  10. }
  11. func (pnt *MyPoint) Read(p []byte) (n int, err error) {
  12. return 42, nil
  13. }
  14. func check(x interface{}) bool {
  15. // 声明一个表示io.Reader的类型对象
  16. reader := reflect.TypeOf((*io.Reader)(nil)).Elem()
  17. // 获取参数所表示对象的指针的类型对象,并判断是否实现了io.Reader接口
  18. return reflect.PtrTo(reflect.TypeOf(x)).Implements(reader)
  19. }
  20. func main() {
  21. x := MyPoint{0, 0}
  22. y := Other(1)
  23. fmt.Println(check(x)) // true
  24. fmt.Println(check(y)) // false
  25. }

关键点在于注意指针的处理方式。

英文:

It is perfectly possible to do what you want with the reflect package. Here is an example:

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "reflect"
  6. )
  7. type Other int
  8. type MyPoint struct {
  9. X, Y int
  10. }
  11. func (pnt *MyPoint) Read(p []byte) (n int, err error) {
  12. return 42, nil
  13. }
  14. func check(x interface{}) bool {
  15. // Declare a type object representing io.Reader
  16. reader := reflect.TypeOf((*io.Reader)(nil)).Elem()
  17. // Get a type object of the pointer on the object represented by the parameter
  18. // and see if it implements io.Reader
  19. return reflect.PtrTo(reflect.TypeOf(x)).Implements(reader)
  20. }
  21. func main() {
  22. x := MyPoint{0, 0}
  23. y := Other(1)
  24. fmt.Println(check(x)) // true
  25. fmt.Println(check(y)) // false
  26. }

The tricky point is to pay attention to how pointers are handled.

答案2

得分: 5

存在一种方法可以在不编译代码的情况下检查 p 是否实现了接口吗?

是的:仔细阅读代码 检查变量是否实现了接口而不进行编译。

这怎么可能呢?如果 p 的方法集包含了接口 i,那么 p 就实现了接口 i。你总是需要编译代码。

我猜你想在运行时而不是在编译时失败。诀窍是获取一个非空的接口类型,然后可以使用 reflect.TypeImplements 方法进行测试:

  1. pt := reflect.TypeOf(&MyPoint{})
  2. ioReaderType := reflect.TypeOf((*io.Reader)(nil)).Elem()
  3. fmt.Println(pt.Implements(ioReaderType)) // ==> true

http://play.golang.org/p/2Qcpfjm4ft

英文:

> Exists one solution to check whether p implements the interface without compiling?

Yes: Careful reading of the code 检查变量是否实现了接口而不进行编译。

How could that be possible? p implements some interface i if the method set of p covers i. You will always have to compile the code.

I assume you want to fail not during compilation but just print during runtime.
The trick is getting a non-nil interface type which can be tested with the Implements method of reflect.Type:

  1. pt := reflect.TypeOf(&MyPoint{})
  2. ioReaderType := reflect.TypeOf((*io.Reader)(nil)).Elem()
  3. fmt.Println(pt.Implements(ioReaderType)) // ==> true

http://play.golang.org/p/2Qcpfjm4ft

huangapple
  • 本文由 发表于 2015年8月20日 16:45:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/32113597.html
匿名

发表评论

匿名网友

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

确定