Go reflection with interface embedded in struct - how to detect "real" functions?
You needn't reflection to my mind
method_in_table := B.Foo
fmt.Printf("%T \n", method_in_table)
will output you
func(main.B) string
Interface type A initialized at predeclared nil which has no dynamic type
var a A
if a==nil{
fmt.Printf("It's nil")
}
a.Foo()
will give you same error. So practical check can be just
if b.A != nil { b.Foo()}
Let me put my two cents in, after you've already received good answers for your question.
Presumably, this is because what is happening with this embed is just like in every other case - a value of type B would have an anonymous interface value of type A, as a field.
You've basically solved the problem here. This is just a field, but because it's anonymous all its methods are being promoted and you can use them directly on the struct. This is not only related to interfaces, but the problem you've pointed to exists within ordinary structures as well:
package main
type A struct {
}
func (a A) Foo() {
}
type B struct {
*A
}
func main() {
B{}.Foo()
}
This will cause panic. I believe this is expected: we're saying B
embeds *A
, but then leave it uninitialised, so what am I thinking? We could try to find an analogy here with, for example, C++ and find out it is similar to a null pointer in C++ – how do we deal with it there? We either expect it to be non-null (by a contract) or need to check before using. The latter it what Uvelichitel suggested in the accepted answer and it's by no means correct and there is no better solution I think. Although it's not very plausible. We do expect the caller to know the method they're calling is a promoted method of an anonymous field which is a pointer (or interface) type and as such can be nil. As an author of such code I would either need to make sure it's never nil (contract) or state it clearly in documentation that a caller needs to check it (but why would I embed this type then instead of having normal field, I'm not sure).
It bothers me with interfaces though, because looking back at your example and making A
an interface, we have a following problem:
package main
import "fmt"
type A interface {
Foo()
}
type B struct {
A
}
func main() {
var b interface{}
b = &B{}
// Nicely check whether interface is implemented
if a, ok := b.(A); ok {
a.Foo()
}
}
Whoops, panic. I explicitly don't use reflect package here to indicate your problem exists within "normal" language usage. I have an interface object b
and want to check whether it implements interface A
. The answer is yes, but I'm getting panic. Who is to blame? I would feel much more comforting saying the creator of object behind the interface b
who advertise some functionality, but don't care to provide the implementation. As such I would like it to call a bad practice or at least force it to be clearly stated in the documentation rather than assuming ok
in the above type assertion means actually ok.
It's getting too long and off topic I think. My answer to your question is then a mixture of already given answers: directly check A
is not null and if it's not possible (you don't know the exact field promoting the method), hope for the best and blame someone else.