英文:
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 Animal
s. 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 Animal
s 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:
&{{dogid} wouf 0}
&{dogid}
Simpler:
func save(animal AnimalGetter) {
fmt.Printf("%v\n", 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 { "id1111" },
"Barky",
4,
}
fmt.Println(reflect.ValueOf(d).FieldByName("Animal").Interface().(Animal))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论