Golang 动态变量参考
Golang dynamic variable reference
在围棋中,我想做这样的事情。我有一个包含许多结构的大对象(使用 Google 的 protobuf
)。这是一个人为的例子:
person.name = "testing"
person.address.street = "123 test st"
person.address.city = "tester"
person.address.zip = 90210
person.billing.address.same = true
我希望能够动态引用事物。例如:
key := "person.address.zip"
fmt.Println("the value of key: " + key) // would like to get 90210
key := "person.address.city"
fmt.Println("the value of key: " + key) // would like to get "tester"
这在 Go 中可行吗?如果是这样,我该怎么做?本质上,我正在创建一个仅包含对象子集的报告,我希望能够创建一个映射文件,用户可以在其中将 keys/values 映射在一起,我的程序将输出该值。我在 python 中工作,但想尝试使用 Go :)
您可以使用 reflect
包中的 func (v Value) FieldByName(name string) Value
:
FieldByName returns the struct field with the given name. It returns
the zero Value if no field was found. It panics if v's Kind is not
struct.
喜欢这个工作示例代码:
package main
import "fmt"
import "reflect"
func main() {
person := Person{}
person.name = "testing"
person.address.street = "123 test st"
person.address.city = "tester"
person.address.zip = 90210
person.billing.address.same = true
v := reflect.ValueOf(person)
f := v.FieldByName("address")
key := f.FieldByName("zip")
fmt.Println(key) // 90210
fmt.Println(f.FieldByName("city")) // tester
}
type Person struct {
name string
address Address
billing Billing
}
type Billing struct {
address Address
}
type Address struct {
street, city string
zip int
same bool
}
输出:
90210
tester
对于你的特殊情况,你可以使用 fmt.Println(field(person, "person.address.zip"))
,就像这个工作示例代码(仅用于演示):
package main
import "fmt"
import "reflect"
import "strings"
func field(t interface{}, key string) reflect.Value {
strs := strings.Split(key, ".")
v := reflect.ValueOf(t)
for _, s := range strs[1:] {
v = v.FieldByName(s)
}
return v
}
func main() {
person := Person{}
person.name = "testing"
person.address.street = "123 test st"
person.address.city = "tester"
person.address.zip = 90210
person.billing.address.same = true
fmt.Println(field(person, "person.address.zip")) //90210
fmt.Println(field(person, "person.address.city")) //tester
}
type Person struct {
name string
address Address
billing Billing
}
type Billing struct {
address Address
}
type Address struct {
street, city string
zip int
same bool
}
输出:
90210
tester
我不熟悉 protobuf 的内部结构,或者它是否提供任何方法来做到这一点。
但是,(1) 如果您想以您描述的方式读取值 - 通过动态链接字段和 (2) 你想多读一遍;我只是将其序列化为 json 并使用 this 包。它速度非常快,并且(几乎)为您提供了您想要的相同语义:
// assuming your object got marshaled to this for example
json := `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
value := gjson.Get(json, "name.last")
println(value.String())
在围棋中,我想做这样的事情。我有一个包含许多结构的大对象(使用 Google 的 protobuf
)。这是一个人为的例子:
person.name = "testing"
person.address.street = "123 test st"
person.address.city = "tester"
person.address.zip = 90210
person.billing.address.same = true
我希望能够动态引用事物。例如:
key := "person.address.zip"
fmt.Println("the value of key: " + key) // would like to get 90210
key := "person.address.city"
fmt.Println("the value of key: " + key) // would like to get "tester"
这在 Go 中可行吗?如果是这样,我该怎么做?本质上,我正在创建一个仅包含对象子集的报告,我希望能够创建一个映射文件,用户可以在其中将 keys/values 映射在一起,我的程序将输出该值。我在 python 中工作,但想尝试使用 Go :)
您可以使用 reflect
包中的 func (v Value) FieldByName(name string) Value
:
FieldByName returns the struct field with the given name. It returns the zero Value if no field was found. It panics if v's Kind is not struct.
喜欢这个工作示例代码:
package main
import "fmt"
import "reflect"
func main() {
person := Person{}
person.name = "testing"
person.address.street = "123 test st"
person.address.city = "tester"
person.address.zip = 90210
person.billing.address.same = true
v := reflect.ValueOf(person)
f := v.FieldByName("address")
key := f.FieldByName("zip")
fmt.Println(key) // 90210
fmt.Println(f.FieldByName("city")) // tester
}
type Person struct {
name string
address Address
billing Billing
}
type Billing struct {
address Address
}
type Address struct {
street, city string
zip int
same bool
}
输出:
90210
tester
对于你的特殊情况,你可以使用 fmt.Println(field(person, "person.address.zip"))
,就像这个工作示例代码(仅用于演示):
package main
import "fmt"
import "reflect"
import "strings"
func field(t interface{}, key string) reflect.Value {
strs := strings.Split(key, ".")
v := reflect.ValueOf(t)
for _, s := range strs[1:] {
v = v.FieldByName(s)
}
return v
}
func main() {
person := Person{}
person.name = "testing"
person.address.street = "123 test st"
person.address.city = "tester"
person.address.zip = 90210
person.billing.address.same = true
fmt.Println(field(person, "person.address.zip")) //90210
fmt.Println(field(person, "person.address.city")) //tester
}
type Person struct {
name string
address Address
billing Billing
}
type Billing struct {
address Address
}
type Address struct {
street, city string
zip int
same bool
}
输出:
90210
tester
我不熟悉 protobuf 的内部结构,或者它是否提供任何方法来做到这一点。
但是,(1) 如果您想以您描述的方式读取值 - 通过动态链接字段和 (2) 你想多读一遍;我只是将其序列化为 json 并使用 this 包。它速度非常快,并且(几乎)为您提供了您想要的相同语义:
// assuming your object got marshaled to this for example
json := `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
value := gjson.Get(json, "name.last")
println(value.String())