检查变量实现接口而不编译

wak*_*wak 4 reflection interface go

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

type MyPoint struct {
   X, Y int
}

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

目的是获取具体类型p实现接口io.Writer的信息.因此,我写了一个简短的主要内容来获得支票.

func main() {
     p := MyPoint{1, 2}
}
Run Code Online (Sandbox Code Playgroud)

第一个想法是在反射和类型开关的帮助下检查它并添加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.")
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

var _ io.Reader = (*MyPoint)(nil)
Run Code Online (Sandbox Code Playgroud)

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

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))
Run Code Online (Sandbox Code Playgroud)

存在一个解决方案来检查p是否在没有编译的情况下实现接口?我希望有人可以帮助我.

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

[1] 检查值是否实现接口的说明.Golang

Did*_*zia 7

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

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
}
Run Code Online (Sandbox Code Playgroud)

棘手的一点是要注意如何处理指针.

  • 只执行 `_, ok := x.(io.Reader)` 有什么问题?如果 `x` 实现了 `io.Reader`,则 `ok` 为真,否则为假。 (3认同)

Vol*_*ker 5

存在一种不用编译就可以检查p是否实现了接口的解决方案?

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

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

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

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

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