2013-09-21 169 views
38

這裏是不工作的簡單圍棋程序:GoLang:訪問結構屬性的名稱

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] 
} 

錯誤:prog.go:18: invalid operation: v[property] (index of type *Vertex)

我要的是使用其名稱來訪問頂點x屬性。如果我做v.X它的作品,但v["X"]不。

有人能告訴我如何使這項工作?

回答

56

大多數代碼不應該需要這種動態查找。與直接訪問相比,它效率低下(編譯器知道Vertex結構中X字段的偏移量,它可以將v.X編譯爲單個機器指令,而動態查找則需要某種類型的哈希表實現或類似的操作)。它也禁止靜態類型:編譯器無法檢查你是否試圖動態訪問未知域,並且它不知道結果類型應該是什麼。

但是......該語言提供了一個reflect模塊,用於您需要這種罕見的時間。

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

沒有錯誤檢查在這裏,所以如果你問的是不存在的字段或字段的類型爲int的不是你會得到一個恐慌。查詢the documentation for reflect瞭解更多詳情。

+2

+1,另請參見[反思法則](http://blog.golang.org/laws-of-reflection),其中介紹了這個想法。 –

+1

這反映模塊是棘手的。我試圖使用它沒有成功。我似乎忘了叫'間接'。感謝您的工作示例和所有解釋。真的很感謝:-) –

+1

感謝上面的解釋代碼。對我而言,它比代碼本身更有用! – Nebulosar

6

Yuo現在有項目oleiade/reflections它允許您獲取/設置結構值或指針字段。
這使得使用reflect package更簡單。

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