gpt4 book ai didi

go - 如何使用反射将结构值转换为结构指针

转载 作者:IT王子 更新时间:2023-10-29 02:12:08 24 4
gpt4 key购买 nike

目标是

Having a variable B that satisfies a specific interface I through pointer receivers type, create another variable C (with reflection and using B), copy B's values into C, modify C (without changing B) and return C as type I.

假设我有以下类型,以下片段模仿生产代码:

import (
"reflect"
)

type IFace interface {
A()
B()
C()
}

type Meta struct {
s string
}

func (m *Meta) A() {}
func (m *Meta) B() {}
func (m *Meta) C() {}

type One struct {
M *Meta
B bool
}

func (o *One) A() {}
func (o *One) B() {}
func (o *One) C() {}

我有一个方法可以执行以下操作:

func Alias(src, dest *Meta) (IFace, error) {
base, err := find(src) //asume that `find` is implemented and err is nil
if err != nil {
return err
}

// trouble starts here ...
// allocate new "instance"
aliased := reflect.New(reflect.TypeOf(base)).Elem().Interface()

// copy the base value
aliased = base

aliasedV := reflect.ValueOf(aliased).Elem()
fm := aliasedV.FieldByName("M")
fm.Set(reflect.ValueOf(dest))

return aliasedV.Interface().(Iface), nil
}

它编译并运行,但是使用以下 TestFunction 它给了我这个错误消息:

interface conversion: One is not IFace: missing method C [recovered]
panic: interface conversion: One is not IFace: missing method C

和测试函数:

func TestOne(t *testing.T) {
srcID := &Meta{S: "SRC"}
destID := &Meta{S: "DEST"}
aliased, err := Alias(srcID, destID)
if err != nil {
t.Error(err)
}

one, isOne := aliased.(*One)
if !isOne {
t.Error("fail")
}
}

有没有办法让包装结构值的interface{} 类型变成包装结构指针的interface{} 类型而不使用底层结构类型直接,比如避免:var any interface{} = aliased.(*One)??,

unsafe 包能帮上忙吗?

感谢 RayfenWindspear,这是一个复制 panic 的 Playground

https://play.golang.org/p/860uAE7qLc

最佳答案

不确定这是否是您想要的,但如果我理解正确的话,在您更新的评论示例中,返回的 base 是您想要复制、修改然后返回副本的内容的,无需更改 base 中的任何内容。如果是这种情况,如果基的基础类型是指针,这段代码 aliased = base 将不会执行您想要的操作,在这种情况下是正确的。

请注意,我修改了 var 名称以更好地反射(reflect)您的分配。

// Having a variable B that satisfies a specific
// interface I through pointer receivers type.
B, err := find(src)
if err != nil {
return nil, err
}

// create another variable C (with reflection and using B),
C := reflect.New(reflect.TypeOf(B).Elem())

// copy B's values into C
bv := reflect.ValueOf(B).Elem()
for i :=0; i < bv.NumField(); i++ {
fv := bv.Field(i)
if fv.Kind() == reflect.Ptr {
v := reflect.New(fv.Elem().Type()) // allocate a new pointer of the same type as the B's pointer field is pointing to, in this case 'Meta'
v.Elem().Set(fv.Elem()) // set the newly allocated pointer's value to the same value as B's pointer field is pointing to, in this case 'Meta{S: "SRC"}'
C.Elem().Field(i).Set(v) // set the newly allocated pointer as the C's field
} else {
C.Elem().Field(i).Set(fv) // non pointer field? just set and that's it
}
// NOTE: if B's field's have subfields that are pointers you'll have to do this for all of them if you want a deep copy
}

// modify C (without changing B)
C.Elem().FieldByName("M").Elem().FieldByName("S").Set(reflect.ValueOf("Hello, 世界"))

这是 Playground :https://play.golang.org/p/bGTdy2vYUu

抱歉,如果这不是您要找的。

关于go - 如何使用反射将结构值转换为结构指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43236589/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com