【问题标题】:Using reflection SetString使用反射 SetString
【发布时间】:2017-10-30 12:31:02
【问题描述】:

我有一个这样的结构:

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")
}

【问题讨论】:

    标签: string go reflection struct


    【解决方案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}
    

    【讨论】:

    • 感谢 Icza 的提示。我知道在分配过程中存在错误,因为例如我尝试创建“虚拟”代码并且我在很短的时间内就做到了:)。顺便说一句,我得到了我的错误所在。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多