英文:
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.Value的FieldByName方法来设置变量的值。在这种情况下,你可以使用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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论