这是一个不起作用的简单go程序:
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]
}
Run Code Online (Sandbox Code Playgroud)
错误:
prog.go:18:无效操作:v [property](类型*Vertex的索引)
我想要的是使用其名称访问Vertex X属性.如果我这样做v.X,但v["X"]没有.
谁能告诉我如何使这项工作?
Pau*_*kin 93
大多数代码不应该需要这种动态查找.与直接访问相比,它是低效的(编译器知道Vertex结构中X字段的偏移,它可以将vX编译为单个机器指令,而动态查找将需要某种哈希表实现或类似).它还禁止静态类型:编译器无法检查您是否未尝试动态访问未知字段,并且无法知道结果类型应该是什么.
但是......语言提供了一个反射模块,用于您需要的罕见时间.
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())
}
Run Code Online (Sandbox Code Playgroud)
这里没有错误检查,所以如果你要求一个不存在的字段,或者字段不是int类型,你会感到恐慌.有关详细信息,请查看文档以获取反映.
Von*_*onC 10
您现在拥有项目oleiade/reflections,它允许您在struct value或指针上获取/设置字段.
它使得使用reflect包不那么棘手.
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
Run Code Online (Sandbox Code Playgroud)
我想提供一种不使用反射的不同方法:
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
fmt.Println(getProperty(&v, "X"))
}
type Getter func(v *Vertex) int
var VertexAccess = map[string]Getter{
"X": func(v *Vertex) int { return v.X },
"Y": func(v *Vertex) int { return v.Y },
}
func getProperty(v *Vertex, property string) int {
return VertexAccess[property](v)
}
Run Code Online (Sandbox Code Playgroud)
https://go.dev/play/p/2E7LZBWx7yZ
这是一个O(1)映射查找和函数调用,其性能应该比反射更好。显然,您需要为您想要支持的每种类型提供一些脚手架代码。从好的方面来说,您可以轻松地重构代码;您的功能是https://martinfowler.com/bliki/TellDontAsk.htmlgetProperty的潜在反模式