Issue
If types T1
and T2
are based on type T
, and type T
only comes into existence from a NewT1()
or NewT2()
, is there any way a function func (*T) WhoAmI()
can know whether it "really" is a T1
or T2
?
package main
import "fmt"
import "reflect"
type T struct{ s string }
func (v *T) WhoAmI() string {
// pull type name with reflect
fmt.Println(reflect.TypeOf(v).Elem().Name()) // always prints "T"!
// todo: if I am actually T1
return "T1"
// todo: else if I am actually T2
return "T2"
}
type T1 T
func NewT1(s string) T1 { return T1{s} }
type T2 T
func NewT2(s string) T2 { return T2{s} }
func main() {
var t1 = T1{"xyz"}
var t2 = T2{"pdq"}
s1 := ((*T)(&t1)).WhoAmI() // would like to return "T1"
s2 := ((*T)(&t2)).WhoAmI() // would like to return "T2"
fmt.Println(s1, s2)
}
to speak technically:
once t1
type T1
is coerced into type T
so func (*T) WhoAmI()
can be called, does t1
completely lose the fact that its type is really T1
? if not, how do we reclaim the knowledge from the perspective of a method receiving type T
?
to speak generally:
in other words, if one type is based on another, if a variable of the derived type is coerced into the base type to run a method, can that method learn the real type of the receiver who called it?
Solution
No, it’s not possible. Creating a new type from an old one is not like creating a new class that inherits from a parent class in an class-based language. In your case T knows nothing about either T1 or T2 and if you’re calling the WhoAmI method you have a receiver of type T by definition.
Your design might work better with an interface. Try something more like this:
type T interface {
WhoAmI() string
}
type T1 struct {
s string
}
func (t *T1) WhoAmI() string { return "T1" }
type T2 struct {
s string
}
func (t *T2) WhoAmI() string { return "T2" }
Try it on the Go playground
T1 and T2 both implement the interface T, so they can be used as type T.
Answered By – Evan Shaw
Answer Checked By – Terry (GoLangFix Volunteer)