2017-05-30 65 views
1

我有這樣一個結構:使用反射的SetString

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

回答

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} 
+0

謝謝你的提示Icza。我知道在設置過程中出現了錯誤,因爲我試圖創建「虛擬」代碼,並且我在很短的時間內完成了它。順便說一句,我得到了我的恐怖分子的地方。謝謝 – Davide