将任何作为接口传递的结构体的变量设置为{}。

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

set variable of any struct passed as interface{}

问题

我想知道如何在使用interface{}值时使用反射设置变量,并且可以传递各种结构体到func F(o interface{})。如何将第一个值(s.A)更改为'hello'?

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A string
}

func main() {
	F(T{"foo"})
}

func F(o interface{}) {

	t := reflect.ValueOf(&T{"bar"}).Elem()
	s := reflect.ValueOf(&o).Elem()
	
	// ok
	fmt.Println("struct:   ", t.Field(0).CanSet())

	// panics - how to set s.A?
	fmt.Println("interface:", s.Field(0).CanSet())
}

你可以使用reflect.ValueFieldByName方法来设置变量的值。在这种情况下,你可以使用FieldByName方法来获取字段的值,并使用SetValue方法来设置新的值。以下是修改后的代码:

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A string
}

func main() {
	F(T{"foo"})
}

func F(o interface{}) {

	t := reflect.ValueOf(&T{"bar"}).Elem()
	s := reflect.ValueOf(&o).Elem()
	
	// ok
	fmt.Println("struct:   ", t.Field(0).CanSet())

	// set s.A
	field := s.FieldByName("A")
	if field.IsValid() && field.CanSet() {
		field.SetString("hello")
	}
	
	fmt.Println("interface:", s.Field(0).CanSet())
	fmt.Println("s.A:", s.Field(0).Interface())
}

这样,你就可以将s.A的值更改为'hello'了。

英文:

I would like to know how to set a variable using reflection when using an interface{} value, and all kind of structs could be passed to func F(o interface{}). How to change the first value (s.A) to 'hello'?

package main

import (
	"fmt"
	"reflect"
)

type T struct {
	A string
}

func main() {
	F(T{"foo"})
}

func F(o interface{}) {

	t := reflect.ValueOf(&T{"bar"}).Elem()
	s := reflect.ValueOf(&o).Elem()
	
	// ok
	fmt.Println("struct:   ", t.Field(0).CanSet())

	// panics - how to set s.A?
	fmt.Println("interface:", s.Field(0).CanSet())
}

答案1

得分: 1

请参考以下链接:http://play.golang.org/p/F6M5mfMOTY

当你将引用值&o传递给reflect.ValueOf时,Go语言将Elem()解释为interface{},而不是你原始的类型。如果你不传递引用,你将得到一个(不可寻址的)实例。我不能百分之百确定为什么会这样,但你可以在上面的链接中看到这种行为。

一种方法是创建一个新的可寻址实例,并遍历s返回的值,在新实例中设置字段,然后返回它。

英文:

See http://play.golang.org/p/F6M5mfMOTY

When you pass the reference value &o, to reflect.ValueOf, Go is interpreting the Elem() as interface{}, not your original type. If you don't pass as a reference, you get a (non-addressable) instance of your type. I am not 100% sure why this is, but you can definitely see the behavior at the play link above.

One approach would be to create a new addressable instance of your type, and then iterate over the value returned by s to set the fields in the new instance and then return it.

huangapple
  • 本文由 发表于 2014年4月18日 23:46:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/23157526.html
匿名

发表评论

匿名网友

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

确定