我有一个像这样的结构:
type ProductionInfo struct {
StructA []Entry
}
type Entry struct {
Field1 string
Field2 int
}
我想使用反射更改Field1
的值,但返回的反射对象始终为CanSet() = false
。我能做什么?参见游乐场示例。
https://play.golang.org/p/eM_KHC3kQ5
以下是代码:
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")
}
答案 0 :(得分:1)
多个错误。让我们迭代它们。
首先,您传递的值为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}