英文:
Golang: convert struct to embedded at offset 0 struct
问题
我有一些不同的结构体,比如Big
,其中包含在偏移量0处嵌入的Small
结构体。如何在不知道Big
类型的代码中访问Small
的结构字段,但已知Small
位于偏移量0处?
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
var v interface{} = Big{}
// 这里我只知道'Small'结构体,并且我知道它位于变量的开头
v.(Small).val // 编译错误
看起来编译器在理论上能够处理这样的表达式,因为它知道Big
类型在偏移量0处嵌入了Small
类型。有没有办法做这样的事情(也许使用unsafe.Pointer
)?
英文:
I have some different structs like Big
with Small
embedded at offset 0.
How can I access Small
's structure fields from code, that doesn't know anything about Big
type, but it is known that Small
is at offset 0?
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
var v interface{} = Big{}
// here i only know about 'Small' struct and i know that it is at the begining of variable
v.(Small).val // compile error
It seems that compiler is theoretically able to operate such expression, because it knows that Big
type has Small
type embedded at offset 0. Is there any way to do such things (maybe with unsafe.Pointer
)?
答案1
得分: 1
避免在可能的情况下使用unsafe
。可以使用反射(reflect
包)来完成上述任务:
var v interface{} = Big{Small{1}, 2}
rf := reflect.ValueOf(v)
s := rf.FieldByName("Small").Interface()
fmt.Printf("%#v\n", s)
fmt.Printf("%#v\n", s.(Small).val)
输出结果(在Go Playground上尝试):
main.Small{val:1}
1
注意:
这适用于任何字段,不仅限于第一个字段(在“偏移量0”处)。这也适用于命名字段,而不仅仅是嵌入字段。但对于未导出的字段,这种方法不起作用。
英文:
Avoid using unsafe
whenever possible. The above task can be done using reflection (reflect
package):
var v interface{} = Big{Small{1}, 2}
rf := reflect.ValueOf(v)
s := rf.FieldByName("Small").Interface()
fmt.Printf("%#v\n", s)
fmt.Printf("%#v\n", s.(Small).val)
Output (try it on the Go Playground):
main.Small{val:1}
1
Notes:
This works for any field, not just the first one (at "offset 0"). This also works for named fields too, not just for embedded fields. This doesn't work for unexported fields though.
答案2
得分: 1
以下是您提供的代码的翻译:
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
func main() {
var v = Big{Small{10}, 200}
print(v.val)
}
这段代码定义了两个结构体类型:Small
和Big
。Small
结构体包含一个整数字段val
,而Big
结构体嵌入了Small
结构体,并且还有一个整数字段bigval
。
在main
函数中,创建了一个Big
类型的变量v
,并初始化为Big{Small{10}, 200}
。然后,打印出v
的val
字段的值为10。
英文:
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
func main() {
var v = Big{Small{10},200}
print(v.val)
}
答案3
得分: 1
虽然使用反射可以实现,但它会带来性能损失,并且在Go语言中不是惯用的方式。
我认为你应该使用接口。像这样:
package main
import (
"fmt"
)
type MySmall interface {
SmallVal() int
}
type Small struct {
val int
}
func (v Small) SmallVal() int {
return v.val
}
type Big struct {
Small
bigval int
}
func main() {
var v interface{} = Big{Small{val: 3}, 4}
fmt.Printf("Small val: %v", v.(MySmall).SmallVal())
}
输出:
Small val: 3
英文:
While answer with reflection is working but it has performance penalties and is not idiomatic to Go.
I believe you should use interface. Like this
https://play.golang.org/p/OG1MPHjDlQ
package main
import (
"fmt"
)
type MySmall interface {
SmallVal() int
}
type Small struct {
val int
}
func (v Small) SmallVal() int {
return v.val
}
type Big struct {
Small
bigval int
}
func main() {
var v interface{} = Big{Small{val: 3}, 4}
fmt.Printf("Small val: %v", v.(MySmall).SmallVal())
}
Output:
Small val: 3
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论