I need to know if either the struct or the pointer to that struct implements a given interface.
// 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
")
return v.Serializebyte()
}
fmt.Printf("I'm not Serializable
")
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
")
return objInt.(Serializable).Serializebyte()
}
fmt.Printf("I'm not Serializable
")
return []byte{0x00}
}
// Stdout:
// I'm not Serializable
// I'm Serializable
Edit: You can run the code above to see what I mean.
Because (*A)
implements Serializable
not A
, the assertion above does not pass but I want to know if either (*A)
implements Serializable
or A
implements it.
Why do I want that? Because if I can do that, the programmers do not need to know how Serializable
works. If not the programers should always need to pass a pointer to Serializable
and implement Serializable
in the struct pointer rather than the struct itself.
It is usually a bad idea to use *T
when the user gives you T
. All modifies on *T
will NOT take effect on user's data.
But if that is what you really want, you can use reflect.
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)
}
Playground: https://play.golang.org/p/rqJe5_KAP6e
EDIT:If you need to make use of that method with pointer reciever, you can use reflect.Value
instead of reflect.Type
. However, it makes an extra copy of the param.
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
}
It is hackable to write a copy-free version code by using refelct.NewAt
and ·reflect.Value.InterfaceData`. But it is highly un-recommended: It will very likely break your future code and is hard to maintain; It uses unsafe package under the hood.
func Serialize(objInt interface{}) []byte {
switch v := objInt.(type) {
case Serializable:
return v.Serializebyte()
}
// do stuf on object that do not implement Serializebyte
}