【问题标题】:Checking of variable implements interface without compiling检查变量实现接口而不编译
【发布时间】:2015-11-13 19:42:33
【问题描述】:

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

type MyPoint struct {
   X, Y int
}

func (pnt *MyPoint) Read(p []byte) (n int, err error) {
    return 42, nil
}

目的是获取具体类型p实现了io.Writer接口的信息。 因此,我写了一个简短的 main trieng 来得到一个真实的检查。

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

第一个想法是在反射和类型开关的帮助下检查它,并将check(p) 添加到主函数中。

func checkType(tst interface{}) {
    switch tst.(type) {
    case nil:
        fmt.Printf("nil")
    case *io.Reader:
        fmt.Printf("p is of type io.Reader\n")
    case MyPoint:
        fmt.Printf("p is of type MyPoint\n")
    default:
        fmt.Println("p is unknown.")
    }
}

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

我找到了一种解决方案,例如at [1] 检查 MyPoint 是否可以在编译时成为 io.Reader。有用。

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

但这不是我想要的解决方案。像下面这样的尝试也失败了。我想是因为上面的原因吧?

i := interface{}(new(MyPoint))
    if _, ok := i.(io.Reader); ok {
        fmt.Println("i is an io.Reader")
}
pType := reflect.TypeOf(p)
if _, ok := pType.(io.Reader); ok {
    fmt.Println("The type of p is compatible to io.Reader")
}

readerType := reflect.TypeOf((*io.Reader)(nil)).Elem()
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]Explanation of checking if value implements interface. Golang

【问题讨论】:

标签: reflection go interface


【解决方案1】:

使用反射包完全可以做你想做的事。这是一个例子:

package main

import (
    "fmt"
    "io"
    "reflect"
)

type Other int

type MyPoint struct {
    X, Y int
}

func (pnt *MyPoint) Read(p []byte) (n int, err error) {
    return 42, nil
}

func check(x interface{}) bool {
    // Declare a type object representing io.Reader
    reader := reflect.TypeOf((*io.Reader)(nil)).Elem()
    // Get a type object of the pointer on the object represented by the parameter
    // and see if it implements io.Reader
    return reflect.PtrTo(reflect.TypeOf(x)).Implements(reader)
}

func main() {

    x := MyPoint{0, 0}
    y := Other(1)

    fmt.Println(check(x)) // true
    fmt.Println(check(y)) // false
}

棘手的一点是要注意指针的处理方式。

【讨论】:

  • 只做_, ok := x.(io.Reader)有什么问题?如果x 实现io.Reader,则ok 为真,否则为假。
【解决方案2】:

是否存在一种解决方案来检查 p 是否在不编译的情况下实现了接口?

是的:仔细阅读代码:-)

这怎么可能?如果 p 的方法集覆盖了 i,则 p 实现了某个接口 i。您将始终需要编译代码。

我假设您不想在编译期间失败,而只是在运行时打印。 诀窍是获得一个非零接口类型,可以使用reflect.TypeImplements 方法进行测试:

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

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

【讨论】:

    猜你喜欢
    • 2011-01-06
    • 2018-10-26
    • 2012-05-08
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多