Types 一种类型被强制转换为另一种类型,是否可以使用一种方法来确定接收器的类型?

Types 一种类型被强制转换为另一种类型,是否可以使用一种方法来确定接收器的类型?,types,go,Types,Go,如果类型T1和T2是基于类型T,而类型T只从NewT1()或NewT2()产生的,那么函数func(*T)WhoAmI()有没有办法知道它“真的”是T1还是T2 package main import "fmt" import "reflect" type T struct { s string } func (v *T) WhoAmI() string { // pull type name with reflect fmt.Println( refle

如果类型
T1
T2
是基于类型
T
,而类型
T
只从
NewT1()
NewT2()
产生的,那么函数
func(*T)WhoAmI()
有没有办法知道它“真的”是
T1
还是
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 ) } 包干管 输入“fmt” 导入“反映” 类型T struct{s string} func(v*T)WhoAmI()字符串{ //使用反射提取类型名称 fmt.Println(reflect.TypeOf(v.Elem().Name())//始终打印“T”! //托多:如果我真的是T1 返回“T1” //托多:否则如果我真的是T2 返回“T2” } T1型 func NewT1(s字符串)T1{return T1{s} t2t型 func NewT2(s字符串)T2{return T2{s} func main(){ var t1=t1{“xyz”} 变量t2=t2{“pdq”} s1:=(*T)(&t1)).WhoAmI()//要返回“t1” s2:=(*T)(&t2)).WhoAmI()//是否要返回“t2” 格式打印LN(s1、s2) } 从技术上讲:

一旦
t1
type
t1
被强制为type
T
那么
func(*T)WhoAmI()
就可以被调用,
t1
是否完全失去了它的类型确实是
t1
的事实?如果不是,我们如何从方法接收类型
T
的角度回收知识

概括地说:


换句话说,如果一种类型基于另一种类型,如果派生类型的变量被强制转换为基类型以运行一个方法,那么该方法能否学习调用它的接收者的真实类型?

不,这是不可能的。从旧类型创建新类型与在基于类的语言中创建从父类继承的新类不同。在您的例子中,T对T1或T2一无所知,如果您正在调用WhoAmI方法,那么根据定义,您有一个类型为T的接收器

使用界面时,您的设计可能会工作得更好。尝试类似以下内容:

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" }
试穿一下


T1和T2都实现了接口T,因此它们可以用作类型T。

Evan的答案很好。然而,有多种方法可以解决这个问题,它们更接近您所寻找的

当你转换时,你实际上改变了类型,没有任何剩余。Go只关心当前类型是什么

解决这个问题的一种方法就是编写一个函数。函数对于共享实现非常有用。一些面向对象的语言认为它们是不纯洁的,但它们不知道它们缺少了什么(我正看着你们呢!)

现在您不必为了调用方法/函数而转换值。当然,如果要进行类型切换并对每个类型执行不同的操作,那么最好只为每个类型编写不同的方法

要使其成为一种方法,您可以执行以下操作:

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))
这样做的好处是你不需要做任何额外的工作。该方法可以同时访问t和self,因此它具有两个方面的优点。但是,这会成为界面的一部分,这有点尴尬

您还可以将其设置为字段:

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
t1
调用
T.M
。但是,请记住,
T.M
始终只会看到一个
T
,而不管您如何调用它(
T
t1
)。为了让
T.M
能够看到
T1

我刚才想的
reflect.TypeOf
,您必须使用上述策略之一。不幸的是,该函数将返回您强制转换到的类型。你确定要选演员吗?如果您使用的是接口,您根本不需要强制转换。如果类型字段不同,强制转换可能会失败,并且强制转换不可能!?然后,您可以尝试一个cast并捕获不可能的情况,从而知道它是哪种类型。在一次没有不同领域或方法的简单尝试中,这并不起作用,因为铸造显然起了作用。你能告诉我是什么类型的
int(一些浮点数)
?谢谢!对于接口,每种类型都必须实现接口的所有方法,这就是我试图解决的问题
type T struct{}
func (t *T) M() {}

type T1 struct { T }
...
var t T
var t1 T1
t.M()
t1.M()