Ответ Эвана хорош. Однако существует несколько способов решения этой проблемы, которые ближе к тому, что вы искали.
Когда вы конвертируете, вы фактически меняете типы, в этом нет ничего остаточного. Go заботится только о том, что является current type.
Один из способов обойти это просто написать функцию. Функции очень полезны для совместной реализации. Некоторые объектно-ориентированные языки отбрасывают их как нечистые, но они не знают, чего им не хватает (я смотрю на вас, публичная статическая пустота!).
func WhoAmI(v interface{}) string {
switch v.(type) {
case *T: return "*T"
case *T1: return "*T1"
case *T2: return "*T2"
}
return "unknown"
}
Теперь вам не нужно преобразовывать значение для вызова метода / функции. Конечно, если вы собираетесь сделать переключение типов и сделать что-то другое для каждого типа, вы можете просто написать разные методы для каждого типа.
Чтобы сделать это методом, вы можете сделать:
type T struct { s string }
func (t *T) WhoAmI() string { return WhoAmI(t) }
type T1 T
func (t1 *T1) WhoAmI() string { return WhoAmI(t1) }
Таким образом, вам не нужно переопределять метод.
Если вы действительно хотите, чтобы T
познал себя, проявите себя! Есть два способа сделать это. Один из них как параметр:
func (t *T) WhoAmI(self interface{}) string { ... }
...
fmt.Println(t.WhoAmI(t))
fmt.Println(((*T)(t1)).WhoAmI(t1))
Плюс в том, что вам не нужно делать никакой дополнительной работы. Метод имеет доступ как к т, так и к себе, поэтому он обладает лучшим из обоих миров. Однако это становится частью вашего интерфейса, что немного неудобно.
Вы также можете сделать это поле:
type T struct { self interface{} }
func NewT() *T {
t := new(T)
t.self = t
return t
}
type T1 T
func NewT1() *T1 {
t1 := new(T1)
t1.self = t1
return t1
}
Теперь любые методы в T
или T1
могут определить, как был изначально создан объект, проверяя self
.
Вы можете продолжать конвертировать туда и обратно, чтобы получить методы, или вы можете использовать функцию под названием встраивание:
type T struct{}
func (t *T) M() {}
type T1 struct { T }
...
var t T
var t1 T1
t.M()
t1.M()
Как видите, вы можете позвонить T.M
через t
или t1
. Однако имейте в виду, что T.M
всегда будет видеть только T
, независимо от того, как вы его называете (t
или t1
). Вам нужно будет использовать одну из вышеуказанных стратегий, чтобы T.M
мог видеть T1
.