英文:
Using reflection SetString
问题
我有一个类似这样的结构体:
type ProductionInfo struct {
StructA []Entry
}
type Entry struct {
Field1 string
Field2 int
}
我想使用反射来更改Field1
的值,但是反射对象始终返回CanSet() = false
。我该怎么办?请参考playground示例。
以下是代码:
func SetField(source interface{}, fieldName string, fieldValue string) {
v := reflect.ValueOf(source)
tt := reflect.TypeOf(source)
for k := 0; k < tt.NumField(); k++ {
fieldValue := reflect.ValueOf(v.Field(k))
fmt.Println(fieldValue.CanSet())
if fieldValue.CanSet() {
fieldValue.SetString(fieldValue.String())
}
}
}
func main() {
source := ProductionInfo{}
source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})
SetField(source, "Field1", "NEW_VALUE")
}
请注意,由于你要求只返回翻译好的部分,因此我只提供了代码的翻译,不会回答你关于代码的问题。
英文:
I have a struct like this one:
type ProductionInfo struct {
StructA []Entry
}
type Entry struct {
Field1 string
Field2 int
}
I would like to change the value of Field1
using reflection but the reflect object returned always CanSet() = false
. What can I do? See playground example.
https://play.golang.org/p/eM_KHC3kQ5
Here is the code:
func SetField(source interface{}, fieldName string, fieldValue string) {
v := reflect.ValueOf(source)
tt := reflect.TypeOf(source)
for k := 0; k < tt.NumField(); k++ {
fieldValue := reflect.ValueOf(v.Field(k))
fmt.Println(fieldValue.CanSet())
if fieldValue.CanSet() {
fieldValue.SetString(fieldValue.String())
}
}
}
func main() {
source := ProductionInfo{}
source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})
SetField(source, "Field1", "NEW_VALUE")
}
答案1
得分: 5
多个错误。让我们逐个解决。
首先,你传递的是 ProductionInfo
的值,而不是你想要修改的 Entry
的值,所以首先将其更改为:
SetField(&source.StructA[0], "Field1", "NEW_VALUE")
接下来,你传递的是一个非指针的值。你不能使用反射修改非指针结构体的字段,因为那只会修改一个将被丢弃的副本。为了避免这种情况(和进一步的混淆),这是不允许的(CanSet()
返回 false
)。所以你必须传递一个指向结构体的指针:
SetField(&source.StructA[0], "Field1", "NEW_VALUE")
现在在 SetField()
内部,reflect.ValueOf(source)
将描述传递的指针。你可以使用 Value.Elem()
导航到指向对象(结构体值)的 reflect.Value
:
v := reflect.ValueOf(source).Elem()
现在它可以工作了。修改后的代码如下:
func SetField(source interface{}, fieldName string, fieldValue string) {
v := reflect.ValueOf(source).Elem()
fmt.Println(v.FieldByName(fieldName).CanSet())
if v.FieldByName(fieldName).CanSet() {
v.FieldByName(fieldName).SetString(fieldValue)
}
}
func main() {
source := ProductionInfo{}
source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})
fmt.Println("Before: ", source.StructA[0])
SetField(&source.StructA[0], "Field1", "NEW_VALUE")
fmt.Println("After: ", source.StructA[0])
}
输出结果(在 Go Playground 上尝试):
Before: {A 2}
true
After: {NEW_VALUE 2}
英文:
Multiple errors. Let's iterate over them.
First, you pass a value of ProductionInfo
and not a value of Entry
whose field you want to modify, so first change it to:
SetField(source.StructA[0], "Field1", "NEW_VALUE")
Next, you are passing a (non-pointer) value. You can't modify the fields of a non-pointer struct with reflection, because that would only modify a copy which would be discarded. In order to avoid this (and further confusion), this is not allowed (CanSet()
returns false
). So you have to pass a pointer to the struct:
SetField(&source.StructA[0], "Field1", "NEW_VALUE")
Now inside SetField()
the reflect.ValueOf(source)
will describe the passed pointer. You may use Value.Elem()
to navigate to the reflect.Value
of the pointed object (the struct value):
v := reflect.ValueOf(source).Elem()
And now it works. Modified code:
func SetField(source interface{}, fieldName string, fieldValue string) {
v := reflect.ValueOf(source).Elem()
fmt.Println(v.FieldByName(fieldName).CanSet())
if v.FieldByName(fieldName).CanSet() {
v.FieldByName(fieldName).SetString(fieldValue)
}
}
func main() {
source := ProductionInfo{}
source.StructA = append(source.StructA, Entry{Field1: "A", Field2: 2})
fmt.Println("Before: ", source.StructA[0])
SetField(&source.StructA[0], "Field1", "NEW_VALUE")
fmt.Println("After: ", source.StructA[0])
}
Output (try it on the Go Playground):
Before: {A 2}
true
After: {NEW_VALUE 2}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论