Go 按名称访问结构属性

Go 按名称访问结构属性,go,go-reflect,Go,Go Reflect,下面是一个简单的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

下面是一个简单的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]
}
错误:

程序go:18:无效操作:v[属性](类型为*顶点的索引)

我想要的是使用其名称访问Vertex X属性。如果我做了
v.X
它会工作,但是
v[“X”]
不会


有人能告诉我怎么做吗?

大多数代码不需要这种动态查找。与直接访问相比,它效率低下(编译器知道顶点结构中X字段的偏移量,它可以将v.X编译为一条机器指令,而动态查找需要某种哈希表实现或类似的实现)。它还禁止静态类型:编译器无法检查您是否没有尝试动态访问未知字段,也无法知道结果类型应该是什么

但是。。。该语言为您提供了一个模块,供您在极少数情况下使用

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类型,您会感到恐慌。请检查更多详细信息。

您现在有了一个项目,该项目允许您获取/设置结构值或指针上的字段。
这使得使用更简单

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

您可以封送结构并将其解组回
map[string]interface{}
。但是,它会将所有数值转换为
float64
,因此您必须手动将其转换为
int

type Vertex struct {
    X int
    Y int
}

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

func getProperty(v *Vertex, property string) float64 {
    m, _ := json.Marshal(v)
    var x map[string]interface{}
    _ = json.Unmarshal(m, &x)
    return x[property].(float64)
}

使用
getAttr
,您可以轻松获取和设置

主程序包
进口(
“fmt”
“反映”
)
func getAttr(obj接口{},字段名字符串)reflect.Value{
pointToStruct:=reflect.ValueOf(obj)//可寻址
curStruct:=pointToStruct.Elem()
如果curStruct.Kind()!=reflect.Struct{
恐慌(“非结构”)
}
curField:=curStruct.FieldByName(fieldName)//类型:reflect.Value
if!curField.IsValid(){
恐慌(“未找到:+fieldName”)
}
返回域
}
func main(){
类型点结构{
X int
y int//如果要保护前缀,请将其设置为小写。
Z字串
}
p:=点{3,5,“Z}
pX:=getAttr(&p,“X”)
//获取测试(int)
fmt.Println(pX.Int())//3
//设定测试
pX.SetInt(30)
fmt.Println(p.X)//30
//测试字符串
getAttr(&p,“Z”).SetString(“Z123”)
fmt.Println(p.Z)//Z123
py:=getAttr(&p,“y”)
如果py.CanSet(){//,则CanSet返回true的必要条件是结构的属性必须具有大写前缀
py.SetInt(50)//它不会在这里执行,因为CanSet返回false。
}
fmt.Println(p.y)//5
}

在+1上运行它,并查看其中的介绍。这个反射模块有点棘手。我试图使用它,但没有成功。好像我忘了调用
Ìndirect
。感谢您的工作示例和所有解释。真的很感激:-)谢谢你对以上代码的解释。对我来说,它甚至比代码本身更有用!