2011-06-18 23 views
63

có thời gian làm việc với các trường struct sử dụng gói reflect. đặc biệt, đã không tìm ra cách đặt giá trị trường.Sử dụng phản ánh, làm cách nào để bạn đặt giá trị của trường cấu trúc?

 
type t struct { fi int; fs string } 
var r t = t{ 123, "jblow" } 
var i64 int64 = 456 
  1. nhận Tên của trường tôi - điều này dường như làm việc

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

  2. nhận được giá trị của trường tôi như một) giao diện {}, b) int - điều này dường như làm việc

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

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

  3. giá trị thiết lập của trường tôi - hãy thử một - hoảng sợ

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

    hoảng loạn: reflect.Value · setInt sử dụng giá trị thu được sử dụng unexported lĩnh vực

    giả sử nó không thích lĩnh vực tên "id" và "name", do đó, được đổi tên thành "Id" và "Tên"

    a) giả định này có đúng không?

    b) nếu đúng, nghĩ không cần thiết vì trong cùng một tập tin/gói

  4. giá trị thiết lập của lĩnh vực i - thử hai (với tên trường vốn) - hoảng sợ

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

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

    hoảng loạn: reflect.Value · SetInt sử dụng giá trị không thể gán được


Hướng dẫn dưới đây bởi @peterSO là kỹ lưỡng và chất lượng cao

Bốn. công trình này:

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

ông ghi chép cũng là tên trường phải xuất khẩu (bắt đầu bằng chữ cái vốn)

+0

ví dụ gần nhất tôi có thể tìm thấy một người nào đó sử dụng 'phản ánh' để đặt dữ liệu là http://comments.gmane.org/gmane.comp.lang.go.general/35045, nhưng ngay cả ở đó, ông cũng đã sử dụng' json.Unmarshal' để thực hiện công việc bẩn thực tế –

+0

(trên nhận xét đã lỗi thời) –

Trả lời

93

Go có sẵn như là open source code. Một cách hay để tìm hiểu về sự phản chiếu là xem cách các nhà phát triển Go cốt lõi sử dụng nó. Ví dụ: gói Go fmtjson. Tài liệu gói có liên kết đến tệp mã nguồn dưới tiêu đề Tệp gói.

Các nguyên soái gói Go json và unmarshals JSON từ và đến cấu trúc Go.


Dưới đây là một ví dụ từng bước mà đặt giá trị của một trường struct trong khi tránh một cách cẩn thận lỗi.

Gói Go reflect có chức năng CanAddr.

func (v Value) CanAddr() bool 

CanAddr trả về true nếu địa chỉ của giá trị có thể thu được với ĐC. Các giá trị như vậy được gọi là địa chỉ. Giá trị là địa chỉ nếu nó là phần tử của một lát, một phần tử của một mảng địa chỉ , một trường có cấu trúc địa chỉ hoặc kết quả là một con trỏ chỉ định . Nếu CanAddr trả về false, hãy gọi Addr sẽ hoảng sợ.

The Go reflect gói có một chức năng CanSet, trong đó, nếu true, ngụ ý rằng CanAddr cũng là true.

func (v Value) CanSet() bool 

CanSet trả về true nếu giá trị của v thể thay đổi. Giá trị chỉ có thể được thay đổi chỉ khi có địa chỉ và không phải là thu được bằng cách sử dụng các trường cấu trúc chưa được công bố . Nếu CanSet trả về sai, hãy gọi cho Đặt hoặc bất kỳ trình đặt cụ thể loại cụ thể nào (ví dụ: SetBool, SetInt64) sẽ không hoạt động.

Chúng tôi cần đảm bảo chúng tôi có thể Set trường struct. Ví dụ,

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 

Nếu chúng ta có thể chắc chắn rằng tất cả các kiểm tra lỗi là không cần thiết, ví dụ đơn giản để,

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

sẽ đến đó ngay bây giờ –

+2

Hãy từ bỏ! một nơi nào đó trong đó là một câu trả lời, nhưng bốn giờ làm việc trên pkg json đã không mang lại cho tôi. tái phản ánh pkg, kéo thông tin là khá đơn giản, nhưng thiết lập dữ liệu đòi hỏi một số ma thuật đen mà tôi rất thích nhìn thấy một ví dụ đơn giản ở đâu đó! –

+2

Xuất sắc! nếu bạn đã từng ở Thái Lan, hãy để tôi đối xử với bạn với một hoặc hai hoặc ba bia! cảm ơn bạn rất nhiều –

6

Điều này dường như làm việc:

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

Prints:

123 
321 
+0

cảm ơn! bây giờ tôi đã đọc các ghi chú của peterso, điều này làm cho cảm giác hoàn hảo. Tôi đã sử dụng foo, không & foo, vì vậy không thể thay đổi, và không chắc chắn những gì Elem() đã được về. –