簡體   English   中英

使用reflect,如何設置struct字段的值?

[英]Using reflect, how do you set the value of a struct field?

使用reflect包處理結構字段時遇到了困難。 特別是,還沒想好如何設置字段值。

type t struct { fi int; fs string }
var r t = t{ 123, "jblow" }
var i64 int64 = 456
  1. 獲取字段 i 的名稱 - 這似乎有效

    var field = reflect.TypeOf(r).Field(i).Name

  2. 將字段 i 的值作為 a) interface{}, b) int - 這似乎有效

    var iface interface{} = reflect.ValueOf(r).Field(i).Interface()

    var i int = int(reflect.ValueOf(r).Field(i).Int())

  3. 設置字段 i 的值 - 嘗試一個 - 恐慌

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    panic : reflect.Value·SetInt 使用使用未導出字段獲得的值

    假設它不喜歡字段名稱“id”和“name”,所以重命名為“Id”和“Name”

    a) 這個假設正確嗎?

    b) 如果正確,認為沒有必要,因為在同一個文件/包中

  4. 設置字段 i 的值 - 嘗試兩個(字段名稱大寫) - 恐慌

    reflect.ValueOf(r).Field(i).SetInt( 465 )

    reflect.ValueOf(r).Field(i).SetInt( i64 )

    恐慌:reflect.Value·SetInt 使用不可尋址的值


@peterSO 下面的說明是全面和高質量的

四。 這有效:

reflect.ValueOf(&r).Elem().Field(i).SetInt( i64 )

他還記錄了字段名稱必須是可導出的(以大寫字母開頭)

Go json 包對 Go 結構中的 JSON 進行編組和解組。

這是一個分步示例,它設置struct字段的值,同時小心地避免錯誤。

Go reflect包有一個CanAddr函數。

func (v Value) CanAddr() bool

如果可以使用 Addr 獲取值的地址,則 CanAddr 返回 true。 這樣的值稱為可尋址的。 如果值是切片的元素、可尋址數組的元素、可尋址結構的字段或取消引用指針的結果,則該值是可尋址的。 如果 CanAddr 返回 false,則調用 Addr 將導致恐慌。

Go reflect包有一個CanSet函數,如果為true ,則意味着CanAddr也是true

func (v Value) CanSet() bool

如果 v 的值可以更改,則 CanSet 返回 true。 只有當值可尋址且不是通過使用未導出的結構字段獲得時,才可以更改值。 如果 CanSet 返回 false,則調用 Set 或任何特定於類型的 setter(例如 SetBool、SetInt64)將發生恐慌。

我們需要確保我們可以Set struct字段。 例如,

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type t struct {
        N int
    }
    var n = t{42}
    // N at start
    fmt.Println(n.N)
    // pointer to struct - addressable
    ps := reflect.ValueOf(&n)
    // struct
    s := ps.Elem()
    if s.Kind() == reflect.Struct {
        // exported field
        f := s.FieldByName("N")
        if f.IsValid() {
            // A Value can be changed only if it is 
            // addressable and was not obtained by 
            // the use of unexported struct fields.
            if f.CanSet() {
                // change value of N
                if f.Kind() == reflect.Int {
                    x := int64(7)
                    if !f.OverflowInt(x) {
                        f.SetInt(x)
                    }
                }
            }
        }
    }
    // N at end
    fmt.Println(n.N)
}

Output:
42
7

如果我們可以確定所有錯誤檢查都是不必要的,則示例簡化為,

package main

import (
    "fmt"
    "reflect"
)

func main() {
    type t struct {
        N int
    }
    var n = t{42}
    fmt.Println(n.N)
    reflect.ValueOf(&n).Elem().FieldByName("N").SetInt(7)
    fmt.Println(n.N)
}

順便說一句,Go 可以作為開源代碼使用 了解反射的一個好方法是了解核心 Go 開發人員如何使用它。 例如,Go fmtjson包。 包文檔在包文件標題下提供了指向源代碼文件的鏈接。

這似乎有效:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    Number int
    Text string
}

func main() {
    foo := Foo{123, "Hello"}

    fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))

    reflect.ValueOf(&foo).Elem().Field(0).SetInt(321)

    fmt.Println(int(reflect.ValueOf(foo).Field(0).Int()))
}

印刷:

123
321

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM