Golang:将结构体转换为偏移量为0的嵌入式结构体

4

我有一些不同的结构体,比如 Big 结构体在偏移量为 0 处嵌入了 Small 结构体。 如果代码不知道 Big 类型,但知道 Small 在偏移量为零处,如何访问 Small 的结构字段?

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

看起来编译器从理论上可以操作这样的表达式,因为它知道Big类型在偏移量0处嵌入了Small类型。 是否有任何方法可以做到这一点(也许使用unsafe.Pointer)?


抱歉,我没有正确阅读问题,请提供需要翻译的英文内容。 - Sridhar
3个回答

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”处)。这也适用于命名字段,而不仅仅是嵌入式字段。但是,这对于未导出的字段无效。

为什么不直接将其转换为Big,然后取v.val或v.Small.val呢?反射在这里有点过头了,不是吗? - Alexander Trakhimenok
@AlexanderTrakhimenok 问询者想要一种不需要了解“Big”的方法。转换或提取类型为“Big”的值并不符合此要求。 - icza

1
type Small struct {
    val int
}

type Big struct {
    Small
    bigval int
}

func main() {
    var v = Big{Small{10},200}
    print(v.val)
}

但是提问者的 v 变量是 interface{} 类型,而你的变量是 Big 类型。 - icza

1
虽然使用反射回答问题是可行的,但它会影响性能并且不符合Go语言的习惯用法。我认为你应该使用接口。像这样:

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())
}

输出:

Small val: 3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接