如何实例化任意类型并设置已知的嵌入字段

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

go (reflect): How to Instantiate an arbitrary type and set a known embedded field

问题

考虑以下类型声明:

type (
	Embedded struct{}
	Actual1 struct{ *Embedded }
	Actual2 struct{ *Embedded }
	Actual3 struct{ *Embedded }
)

现在考虑以下函数,其中 i 可能是类型 Actual1Actual2Actual3(或任何其他以类似方式嵌入 Embedded 的类型)。我无法进行类型断言或类型切换,因为我无法知道有多少类型包含 Embedded,我只知道关于 i 的是它确实嵌入了 Embedded 类型。该函数将实例化一个与 i 相同类型的新实例,并在该新实例上设置 embed

func New(i interface{}, field *Embedded) interface{} {
	// 步骤 1. 实例化与 `i` 具有相同底层类型的新实例
	// 步骤 2. 将 `i.Embedded` 设置为 `field`
	// 步骤 3. 返回新实例。
}

下面是用法示例:

func main() {
	actual := &Actual1{}
	embed := &Embedded{}
	copied := New(actual, embed)
	if copied.(Actual1).Embedded != embed {
		log.Fatal("It didn't work!")
	}
}

一个正确的 New(...) 函数的实现不能使用类型断言或类型切换,并且也不会导致上述调用 log.Fatal

我认为我正在请求的是这两个问题的结合:

英文:

Consider the following type declaration:

type (
	Embedded struct{}
	Actual1 struct{ *Embedded }
	Actual2 struct{ *Embedded }
	Actual3 struct{ *Embedded }
)

Now consider the following function, where i may be of type Actual1, Actual2, or Actual3 (or any other type that embeds Embedded in like manner). I can't do a type assertion or a type switch because I can't know how many types contain Embedded, all I know about i is that it does indeed embed the Embedded type. This function will instantiate a new instance of the same type as i and set embed on that newly instantiated copy instance.

func New(i interface{}, field *Embedded) interface{} {
	// Step 1. instantiate new instance of `i`, of same underlying type as `i`
	// Step 2. set `i.Embedded` to `field`
	// Step 3. return the new instance.
}

Here's what usage would look like:

func main() {
	actual := &Actual1{}
	embed := &Embedded{}
	copied := New(actual, embed)
	if copied.(Actual1).Embedded != embed {
		log.Fatal("It didn't work!")
	}
}

A correct implementation of the New(...) function cannot use type assertions or a type switch and would also not result in the call to log.Fatal shown above.

I think what I'm asking for is a combination of these two questions:

答案1

得分: 2

使用反射,你可以这样做:

  • 从指向结构体的指针的类型中获取结构体的类型
  • 实例化并解引用它
  • 使用指定的字段名称查找字段,并将其值设置为指针的值

代码:

v := reflect.New(reflect.TypeOf(i).Elem()).Elem()
f := reflect.ValueOf(field)
v.FieldByName("Embedded").Set(f)
return v.Interface()

Playground: http://play.golang.org/p/fX413svXDv

英文:

Using reflection, you can do it like that:

  • get the type of the struct from the type of the pointer to it
  • instantiate and deref it
  • set the value of the field (looking it up by name) with the value of your pointer

Code:

v := reflect.New(reflect.TypeOf(i).Elem()).Elem()
f := reflect.ValueOf(field)
v.FieldByName("Embedded").Set(f)
return v.Interface()

Playground: http://play.golang.org/p/fX413svXDv

huangapple
  • 本文由 发表于 2015年8月22日 00:13:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/32144977.html
匿名

发表评论

匿名网友

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

确定