通过反射将字符串赋值给结构体。

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

Assign a string to a struct via reflect

问题

我有一个结构体,在其中我希望使用反射动态地将一个字符串更改为另一个字符串。我的问题是新字符串是在堆栈上创建的,因此Set()方法会引发恐慌。

这对我来说是有道理的,但我不知道如何解决它。我不确定如何轻松地声明一个可寻址的字符串,或者是否有其他反射技术可供使用。

type MyStruct struct {
    SomeField string
}

func main() {
    myStruct := MyStruct{"initial"}
    hello := "hello world"
    
    field := reflect.ValueOf(myStruct).FieldByName("SomeField")
    helloValue := reflect.ValueOf(hello)
    fmt.Printf("hello is on the stack, canAddr is %v\n", helloValue.CanAddr())
    
    // 这将引发恐慌,因为canAddr为false
    field.Set(helloValue)
}

https://play.golang.org/p/ghUgiQfKXhk

英文:

I have a struct, where I wish to dynamically change a string to another string using reflect. My issue is that the new string is created on the stack, and therefore the Set() method panics.

This makes sense to me, but I don't know how to fix it. I'm not sure the easy way to declare a string as addressable or if there's a different reflection technique to use.

type MyStruct struct {
	SomeField string
}

func main() {
	myStruct := MyStruct{"initial"}
	hello := "hello world"
	
	field := reflect.ValueOf(myStruct).FieldByName("SomeField")
	helloValue := reflect.ValueOf(hello)
	fmt.Printf("hello is on the stack, canAddr is %v\n", helloValue.CanAddr())
	
	// This will panic because canAddr is false
	field.Set(helloValue)
}

https://play.golang.org/p/ghUgiQfKXhk

答案1

得分: 2

go错误有点误导人。问题出在结构体上,而不是字符串。

问题出在这一行:
field := reflect.ValueOf(myStruct).FieldByName("SomeField")
调用ValueOf传入了一个副本(在这种情况下是myStruct的副本)。由于更改副本不会更改myStruct,所以go会发生恐慌(虽然有帮助,但有点晦涩)。参见反射的第三定律

将这一行更改为field := reflect.ValueOf(&myStruct).Elem().FieldByName("SomeField")可以修复错误(注意使用&获取地址,然后使用Elem()解引用)。

当然,我在发布问题后才弄清楚这一点,但希望能帮助其他人。

英文:

The go error is a bit of a misnomer. The problem is with the struct, not the string.

The problem is in this line:
field := reflect.ValueOf(myStruct).FieldByName("SomeField")
Calling ValueOf passes in a copy (of myStruct in this case). Since changing a copy won't change myStruct, then go panics (helpfully, if cryptically). See [the third law of reflection] (https://blog.golang.org/laws-of-reflection#TOC_8)

Changing this line to field := reflect.ValueOf(&myStruct).Elem().FieldByName("SomeField") fixes the error (note the & to take the address, and then Elem() to dereference)

Of course I only figure this out after posting the question but hopefully it will help someone else

huangapple
  • 本文由 发表于 2021年7月20日 00:02:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/68443632.html
匿名

发表评论

匿名网友

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

确定