如何知道结构或指向结构的指针是否实现了接口

时间:2019-02-07 01:38:11

标签: go reflection

我需要知道该结构或该结构的指针是否实现了给定的接口。

// You can edit this code!
// Click here and start typing.
package main

import "fmt"

func main() {
 var a A = A{
  i: 5,
 }
 Serialize(a)
 Serialize(&a)
}

type Serializable interface {
 //Serialize() string
 //Deserialize(string)

 Serializebyte() []byte
 Deserializebyte(b []byte) (bytesRead int)
}

type A struct {
 i int
}

func (*A) Serializebyte() []byte {
 return []byte{0x00}
}

func (*A) Deserializebyte(b []byte) (bytesRead int) {
 return 0
}

func Serialize(objInt interface{}) []byte {
 // this doesn't work

 switch v := (objInt).(type) {
 case Serializable:
  fmt.Printf("I'm Serializable\n")
  return v.Serializebyte()
 }

 fmt.Printf("I'm not Serializable\n")
 return []byte{0x00}
}

// this other way also dont work
func Serialize2(objInt interface{}) []byte {
// this doesn't work
    _, isSerializable := objInt.(Serializable)
    if isSerializable{
        fmt.Printf("I'm Serializable\n")
        return objInt.(Serializable).Serializebyte()
}

    fmt.Printf("I'm not Serializable\n")
    return []byte{0x00}
}



// Stdout:
// I'm not Serializable
// I'm Serializable

编辑: 您可以运行上面的代码以了解我的意思。

由于(*A)实现了Serializable而不是A,以上声明没有通过,但是我想知道(*A)是实现了Serializable还是{{1 }}实现。

我为什么要那样?因为如果可以的话,程序员不需要知道A的工作方式。如果不是这样,那么程序员应该始终需要将指针传递给Serializable并在结构指针而不是结构本身中实现Serializable

2 个答案:

答案 0 :(得分:1)

当用户给您*T时使用T通常是一个坏主意。 *T上的所有修改将对用户数据生效。

但是,如果那是您真正想要的,则可以使用反射。

func testFool(a interface{}) bool {
    if _, ok := a.(Fool); ok {
        return true
    }
    t := reflect.PtrTo(reflect.TypeOf(a))
    FoolType := reflect.TypeOf((*Fool)(nil)).Elem()
    return t.Implements(FoolType)
}

游乐场:https://play.golang.org/p/rqJe5_KAP6e

编辑:如果需要使用带有指针接收器的该方法,则可以使用reflect.Value代替reflect.Type。但是,它会复制该参数。

func testFool(a interface{}) bool {
    if _, ok := a.(Fool); ok {
        return true
    }
    t := reflect.TypeOf(a)
    v := reflect.New(t)
    v.Elem().Set(reflect.ValueOf(a))
    ptrA := v.Interface()
    if foo, ok := ptrA.(Fool); ok {
        foo.Foo()
        return true
    }
    return false
}

使用refelct.NewAt和·reflect.Value.InterfaceData`来编写无副本的版本代码是很容易的。但这是极不推荐的:它很可能会破坏您将来的代码,并且难以维护。它使用引擎盖下的不安全包装。

答案 1 :(得分:0)

func Serialize(objInt interface{}) []byte {
    switch v := objInt.(type) {
    case Serializable:
        return v.Serializebyte()
    }

    // do stuf on object that do not implement Serializebyte
}

https://tour.golang.org/methods/16