如何获取父嵌入结构体字段的值?

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

How to get parent embedded struct field value?

问题

我在我的包中有以下的结构体。

type Animal struct {
  Id string
  // 还有一些其他的公共字段
}

使用我的包的用户应该能够实现自己的 Animal。由于我在一个方法中需要使用 Id,用户必须嵌入我的结构体。

type Dog struct {
  Animal
  Name string
  Legs int
}

在我的包中,我有一个 save() 函数,用于将 Animal 保存到数据库中。由于我不知道用户的类型,我必须使用 interface{} 作为参数类型。我的问题是:如何获取父结构体 Animal 中的 Id?目前我使用一些 JSON 解析和反序列化的方法,但这是正确的做法吗?

func put(doc interface{}) error {
  res, err := json.Marshal(doc)
  if err != nil {
    return err
  }
  var animal *Animal
  err = json.Unmarshal(res, &animal)
  if err != nil {
    return err
  }
  fmt.Println(animal.Id) // 最终我得到了 Id
  // ...
}

用法:

func main() {
  bello := Dog{
    Animal: Animal{
      Id: "abcd1234",
    },
    Name: "bello",
    Legs: 4,
  }
  err := put(bello)
  // ...
}
英文:

I have the following struct in my package.

type Animal struct {
  Id string
  // and some more common fields
}

A user who uses my package should be able to implement own Animals. As I need Id in one of my methods the user has to embed my struct.

type Dog struct {
  Animal
  Name string
  Legs int
}

In my package I have a save() function that saves Animals to database. As I don't know the user's type I have to use interface{} as argument type. My question is: How do I get the Id (from the parent struct Animal)? At the moment I use some JSON parsing and unmarshalling, but is this the way to go/Go?

func put(doc interface{}) error {
  res, err := json.Marshal(doc)
  if err != nil {
    return err
  }
  var animal *Animal
  err = json.Unmarshal(res, &animal)
  if err != nil {
    return err
  }
  fmt.Println(animal.Id) // finally I have the Id
  // ...
}

Usage

func main() {
  bello := Dog{
    Animal: Animal{
      Id: "abcd1234",
    },
    Name: "bello",
    Legs: 4,
  }
  err := put(bello)
  // ...
}

答案1

得分: 4

也许你可以添加一个接口来确保获取到父结构体的引用:

type AnimalGetter interface {
    GetAnimal() *Animal
}

func (dog *Dog) GetAnimal() *Animal {
    return &dog.Animal
}

这样,你的保存方法就可以进行类型断言(AnimalGetter):

func save(obj interface{}) {
    animal := obj.(AnimalGetter)
    fmt.Printf("%v\n", animal.GetAnimal())
}

在[kbd]play.golang.org[/kbd]中可以看到完整的示例。

输出:

&{{dogid} wouf 0}
&{dogid}

更简单的写法:

func save(animal AnimalGetter) {
    fmt.Printf("%v\n", animal.GetAnimal())
}

在[kbd]play.golang.org[/kbd]中可以看到示例。

英文:

Maybe you can add an interface in order to be sure to get a reference to the parent struct:

type AnimalGetter interface {
	GetAnimal() *Animal
}

func (dog *Dog) GetAnimal() *Animal {
	return &dog.Animal
}

That would allow your save method to do a type assertion (AnimalGetter):

func save(obj interface{}) {
	animal := obj.(AnimalGetter)
	fmt.Printf("%v\n", animal.GetAnimal())
}

See a complete example in <kbd>play.golang.org</kbd>.

Output:

&amp;{{dogid} wouf 0}
&amp;{dogid}

Simpler:

func save(animal AnimalGetter) {
	fmt.Printf(&quot;%v\n&quot;, animal.GetAnimal())
}

(<kbd>play.golang.org</kbd>)

答案2

得分: 2

这里的方法是将Animal声明为一个接口:

type Animal interface {
    ID() int
    Name() string
    // 其他Animal字段的获取方法在这里
}

然后,save函数可以将Animal作为参数,并使用Animal的方法获取所需的所有信息。

另一种可能的方法是使用reflect包从结构体中获取Animal字段,但这种方法可能会更容易出错、更混乱,并且可能比使用接口更慢。

英文:

The way to go/Go here is to declare Animal as an interface:

type Animal interface {
    ID() int
    Name() string
    // Other Animal field getters here.
}

Then, save can take Animal as an argument and get all the info it needs using Animal's methods.

The other possbile way is to use the reflect package to obtain the Animal fields from the struct, but this will be buggier, dirtier and possibly slower that using an interface.

答案3

得分: 1

你可以使用这个小的反射技巧来实现,尽管像@VonC建议的使用接口可能是一种更实用和惯用的方法。

无论如何,下面是使用反射实现相同效果的代码:

func main() {
    d := Dog {
        Animal { "id1111" },
        "Barky",
        4,
    }
    fmt.Println(reflect.ValueOf(d).FieldByName("Animal").Interface().(Animal))
}

希望对你有帮助!

英文:

You can do it with this small reflection trick, although perhaps using interfaces like @VonC suggested might be a more practical and idiomatic approach.

Anyway, here's the same achieved with reflection:

func main() {

	d := Dog {
		Animal { &quot;id1111&quot; },
		&quot;Barky&quot;,
		4,
	}
	fmt.Println(reflect.ValueOf(d).FieldByName(&quot;Animal&quot;).Interface().(Animal))
}

huangapple
  • 本文由 发表于 2014年9月8日 22:10:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/25726251.html
匿名

发表评论

匿名网友

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

确定