检查value是否实现接口的说明

Tim*_*nov 20 interface type-conversion go

我读过"Effective Go"和其他问答:golang界面兼容性编译类型检查,但是我无法正确理解如何使用这种技术.

请看例子:

type Somether interface {
    Method() bool
}

type MyType string

func (mt MyType) Method2() bool {
    return true
}

func main() {
    val := MyType("hello")

    //here I want to get bool if my value implements Somether
    _, ok := val.(Somether)
    //but val must be interface, hm..what if I want explicit type?

    //yes, here is another method:
    var _ Iface = (*MyType)(nil)
    //but it throws compile error
    //it would be great if someone explain the notation above, looks weird
}
Run Code Online (Sandbox Code Playgroud)

是否有任何简单的方法(例如,不使用反射)检查值,如果它实现了一个接口?

Dea*_*baz 26

如果您不知道值的类型,则只需检查值是否实现接口.如果类型已知,则该检查由编译器自动完成.

如果你真的想要检查,你可以使用你给出的第二种方法:

var _ Somether = (*MyType)(nil)
Run Code Online (Sandbox Code Playgroud)

在编译时会出错:

prog.go:23: cannot use (*MyType)(nil) (type *MyType) as type Somether in assignment:
    *MyType does not implement Somether (missing Method method)
 [process exited with non-zero status]
Run Code Online (Sandbox Code Playgroud)

你在这里做的是将MyType类型(和nil值)的指针分配给类型的变量Somether,但由于变量名称_被忽略.

如果MyType实现Somether,它将编译并不执行任何操作

  • 你可以把接口值想象成一个容器,你可以把任何你想要的东西放进去,只要它实现了正确的方法。它可以包含指向结构的指针,或直接包含结构。根据经验,您永远不需要创建指向接口值的指针 (2认同)

小智 15

以下将起作用:

val:=MyType("hello")
var i interface{}=val
v, ok:=i.(Somether)
Run Code Online (Sandbox Code Playgroud)


dmi*_*igo 9

It is also possible to use Implements(u Type) bool method of reflect.Type in the following way:

package main

import (
    "reflect"
)

type Somether interface {
    Method() bool
}

type MyType string

func (mt MyType) Method() bool {
    return true
}

func main() {

    inter := reflect.TypeOf((*Somether)(nil)).Elem()

    if reflect.TypeOf(MyType("")).Implements(inter) {
        print("implements")
    } else {
        print("doesn't")
    }
}
Run Code Online (Sandbox Code Playgroud)

You can read more on that in the documentation.


小智 9

你也可以采用Alpha的解决方案:

val := MyType("hello")
var i interface{} = val
v, ok := i.(Somether)
Run Code Online (Sandbox Code Playgroud)

...并进一步减少它:

val := MyType("hello")
v, ok := interface{}(val).(Somether)
Run Code Online (Sandbox Code Playgroud)

如果您尝试测试一次性方法,您甚至可以执行以下操作:

val := MyType("hello")
v, ok := interface{}(val).(interface {
    Method() bool
}) 
Run Code Online (Sandbox Code Playgroud)

注意:确保您对“指针接收器”与“值接收器”实现非常小心。如果实现使用指针,则在传入值对象时断言将失败。如果实现使用值接收器,则两个断言都将通过。

// Implement Somether as a POINTER receiver method
func (mt *MyType) Method() bool {
  return true
}

func main() {
    val := MyType("hello")

    v, ok := interface{}(val).(Somether)
    fmt.Println(v, ok)
    // Output:  <nil> false

    // Notice the pass by reference
    v, ok := interface{}(&val).(Somether)
    fmt.Println(v, ok)
    // Output:  0xc000010200 true

}
Run Code Online (Sandbox Code Playgroud)

相对

// Implement Somether as a VALUE receiver method
func (mt MyType) Method() bool {
  return true
}

func main() {
    val := MyType("hello")

    v, ok := interface{}(val).(Somether)
    fmt.Println(v, ok)
    // Output:  hello true

    // Notice the pass by reference
    v, ok := interface{}(&val).(Somether)
    fmt.Println(v, ok)
    // Output:  0xc00008e1e0 true

}
Run Code Online (Sandbox Code Playgroud)