在Go中,我如何使用匿名字段方法获取类型的TypeOf?

huangapple go评论83阅读模式
英文:

In Go, how can I get the TypeOf a type using an anonymous field method?

问题

如何使用匿名字段(或超类)获取结构体的正确类型?

我试图让这个鱼描述自己为鳕鱼:

package main

import (
	"fmt"
	"reflect"
)

type Fish struct {
}

func (self *Fish) WhatAmI() string {
	return reflect.TypeOf(self).String()
}

type Cod struct {
	Fish
}

func main() {
	c := new(Cod)
	fmt.Println("我是一个", c.WhatAmI())
}

我得到的输出是:

我是一个 *main.Fish

我想要的是:

我是一个 *main.Cod
英文:

How do I get the correct Type of the struct using the anonymous field (or superclass)?

I am trying to make this fish describe itself as a cod:

package main

import (
	"fmt"
	"reflect"
)

type Fish struct {
}

func (self *Fish) WhatAmI() string {
	return reflect.TypeOf(self).String()
}

type Cod struct {
	Fish
}

func main() {
	c := new(Cod)
	fmt.Println("I am a", c.WhatAmI())
}

The output I get is:

I am a *main.Fish

What I want is:

I am a *main.Cod

答案1

得分: 9

你得到了正确的答案。你想要得到的答案是错误的。

func (f *Fish) WhatAmI() string {
        return reflect.TypeOf(f).String()
}

f 是类型为 *main.Fish 的,甚至在声明时就指定了它的类型为 f *Fish。因此它永远不可能是类型为 *main.Cod 的。

混淆的可能来源是:Cod 的方法集继承了它的匿名嵌入字段 Fish 的方法集,并且没有覆盖它。因此,在 Cod 的实例上调用 WhatAmI 方法会将调用委托给 Fish.WhatAmI,但是接收者现在是类型为 *main.Fish 的嵌入字段。

覆盖继承方法的示例:

package main

import (
        "fmt"
)

type Fish struct {
}

func (f *Fish) WhatAmI() string {
        return fmt.Sprintf("%T", f)
}

type Cod struct {
        Fish
}

func (c *Cod) WhatAmI() string {
        return fmt.Sprintf("%T", c)
}

func main() {
        c := new(Cod)
        fmt.Println("I am a", c.WhatAmI())
}

Playground


输出:

I am a *main.Cod
英文:

You are getting the correct answer. The answer you want to get is wrong.

In

func (f *Fish) WhatAmI() string {
        return reflect.TypeOf(f).String()
}

f is of type *main.Fish, it's even declared to be of that type (f *Fish). Thus it cannot ever be of type *main.Cod.

The probable source of confusion: The method set of Cod inherites the method set of its embedded, anonymous field Fish and doesn't override it. Thus invoking WhatAmI on an instance of Cod "delegates" the call to Fish.WhatAmI, but the receiver is now the embedded field of type *main.Fish.

Example with overriding the inherited method:

package main

import (
        "fmt"
)

type Fish struct {
}

func (f *Fish) WhatAmI() string {
        return fmt.Sprintf("%T", f)
}

type Cod struct {
        Fish
}

func (c *Cod) WhatAmI() string {
        return fmt.Sprintf("%T", c)
}

func main() {
        c := new(Cod)
        fmt.Println("I am a", c.WhatAmI())
}

Playground


Output:

I am a *main.Cod

答案2

得分: 2

对于一个相当通用的解决方案,你可以将WhatAmI函数从Fish类型中分离出来,并使用一个空接口(参见Andrew Gerrand的《反射法则》),然后在该接口上检查类型:

package main

import (
	"fmt"
	"reflect"
)

type Fish struct {
}

type Cod struct {
	Fish
}

func WhatAmI (self interface{}) string {
	return reflect.TypeOf(self).String()
}

func main() {
	c := new(Cod)
	fmt.Println("I am a", WhatAmI(c))
}

输出:

I am a *main.Cod
英文:

For a fairly generic solution, you could separate the WhatAmI function from the Fish type and use an empty interface (see Andrew Gerrand's "The Laws of Reflection"), and just check the type on that:

package main

import (
	"fmt"
	"reflect"
)

type Fish struct {
}

type Cod struct {
	Fish
}

func WhatAmI (self interface{}) string {
	return reflect.TypeOf(self).String()
}

func main() {
	c := new(Cod)
	fmt.Println("I am a", WhatAmI(c))
}

Gives:

I am a *main.Cod

huangapple
  • 本文由 发表于 2013年6月4日 19:18:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/16916464.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定