2013-09-21 39 views
38

Tiếp cận struct Dưới đây là một chương trình đi đơn giản không hoạt động:GoLang: bất động sản theo tên

package main 
import "fmt" 

type Vertex struct { 
    X int 
    Y int 
} 

func main() { 
    v := Vertex{1, 2} 
    fmt.Println(getProperty(&v, "X")) 
} 

func getProperty(v *Vertex, property string) (string) { 
    return v[property] 
} 

Lỗi: prog.go:18: invalid operation: v[property] (index of type *Vertex)

Những gì tôi muốn là để truy cập vào các tài sản Vertex X sử dụng tên của nó. Nếu tôi làm v.X nó hoạt động, nhưng v["X"] thì không.

Ai đó có thể cho tôi biết cách thực hiện tác phẩm này không?

Trả lời

56

Hầu hết mã không cần loại tìm kiếm động này. Nó không hiệu quả so với truy cập trực tiếp (trình biên dịch biết sự bù đắp của trường X trong cấu trúc Vertex, nó có thể biên dịch v.X sang một lệnh máy, trong khi tra cứu động sẽ cần một số kiểu triển khai bảng băm hoặc tương tự). Nó cũng ức chế gõ tĩnh: trình biên dịch không có cách nào để kiểm tra xem bạn không cố gắng truy cập các trường không xác định một cách động, và nó không thể biết kiểu kết quả sẽ là gì.

Nhưng ... ngôn ngữ cung cấp mô-đun reflect trong thời gian hiếm hoi mà bạn cần.

package main 

import "fmt" 
import "reflect" 

type Vertex struct { 
    X int 
    Y int 
} 

func main() { 
    v := Vertex{1, 2} 
    fmt.Println(getField(&v, "X")) 
} 

func getField(v *Vertex, field string) int { 
    r := reflect.ValueOf(v) 
    f := reflect.Indirect(r).FieldByName(field) 
    return int(f.Int()) 
} 

Không có lỗi khi kiểm tra ở đây, vì vậy bạn sẽ cảm thấy hoảng sợ nếu bạn yêu cầu trường không tồn tại hoặc trường không thuộc loại int. Kiểm tra the documentation for reflect để biết thêm chi tiết.

+2

+1 và xem thêm [Luật phản ánh] (http://blog.golang.org/laws-of-reflection) giới thiệu ý tưởng. –

+1

Điều này phản ánh mô-đun là loại khó khăn. Tôi đã cố gắng sử dụng nó mà không thành công. Có vẻ như tôi đã quên gọi 'Ìndirect'. Cảm ơn ví dụ làm việc và tất cả các giải thích. Thực sự đánh giá cao :-) –

+1

Cảm ơn bạn đã giải thích ở trên mã. Đối với tôi, nó thậm chí còn hữu ích hơn bản thân mã! – Nebulosar

6

Yuo hiện có dự án oleiade/reflections cho phép bạn nhận/đặt trường trên giá trị struct hoặc con trỏ.
Việc sử dụng reflect package ít phức tạp hơn.

s := MyStruct { 
    FirstField: "first value", 
    SecondField: 2, 
    ThirdField: "third value", 
} 

fieldsToExtract := []string{"FirstField", "ThirdField"} 

for _, fieldName := range fieldsToExtract { 
    value, err := reflections.GetField(s, fieldName) 
    DoWhatEverWithThatValue(value) 
} 


// In order to be able to set the structure's values, 
// a pointer to it has to be passed to it. 
_ := reflections.SetField(&s, "FirstField", "new value") 

// If you try to set a field's value using the wrong type, 
// an error will be returned 
err := reflection.SetField(&s, "FirstField", 123) // err != nil 
Các vấn đề liên quan