反映:设置指针的字段
Reflect: setting a field of a pointer
我正在尝试做这样的事情:
使用名为 env
:
的标签定义结构
type Env struct {
Port string `env:"PORT"`
}
调用一些函数,它将使用 os.Getenv
获取环境变量名称并将其设置在结构中。
现在,我有这个:
package main
import (
"fmt"
"os"
"reflect"
)
func ParseEnv(t interface{}, v interface{}) {
it := reflect.TypeOf(t)
for i := 0; i < it.NumField(); i++ {
field := it.Field(i)
value := os.Getenv(field.Tag.Get("env"))
if value == "" {
continue
}
reflect.ValueOf(v).Elem().FieldByName(field.Name).SetString(value)
}
}
type Env struct {
Port string `env:"PORT"`
DatabaseURL string `env:"DATABASE_URL"`
}
func main() {
os.Setenv("PORT", "8080")
os.Setenv("DATABASE_URL", "postgres://user:pass@host:5432/my-db")
env := Env{}
ParseEnv(env, &env)
fmt.Println(env)
}
http://play.golang.org/p/b8uPPVo4aV
但是,如您所见,我必须将引用和指针都传递给我的函数。
虽然这有效,但它非常难看(至少我认为是)。
如果我试图只传递指针,我就不能得到正确的类型(因为它将是一个 *interface{}
),而且,如果我只传递引用,我就不能设置值使用 reflect
(即使我可以,它也行不通)。
有没有明智的方法来做到这一点?
下面是一个 "saner" 方法来做你想做的事。您会注意到,我们不需要传入结构的两个副本,而只需要一个指向结构的指针。
func ParseEnv(val interface{}) {
ptrRef := reflect.ValueOf(val)
if ptrRef.Kind() != reflect.Ptr {
panic("pointer to struct expected")
}
ref := ptrRef.Elem()
if ref.Kind() != reflect.Struct {
panic("pointer to struct expected")
}
refType := ref.Type()
for i := 0; i < refType.NumField(); i++ {
field := refType.Field(i)
value := os.Getenv(field.Tag.Get("env"))
if value == "" {
continue
}
ref.Field(i).SetString(value)
}
}
以上函数应按以下方式调用:
ParseEnv(&env)
我正在尝试做这样的事情:
使用名为 env
:
type Env struct {
Port string `env:"PORT"`
}
调用一些函数,它将使用 os.Getenv
获取环境变量名称并将其设置在结构中。
现在,我有这个:
package main
import (
"fmt"
"os"
"reflect"
)
func ParseEnv(t interface{}, v interface{}) {
it := reflect.TypeOf(t)
for i := 0; i < it.NumField(); i++ {
field := it.Field(i)
value := os.Getenv(field.Tag.Get("env"))
if value == "" {
continue
}
reflect.ValueOf(v).Elem().FieldByName(field.Name).SetString(value)
}
}
type Env struct {
Port string `env:"PORT"`
DatabaseURL string `env:"DATABASE_URL"`
}
func main() {
os.Setenv("PORT", "8080")
os.Setenv("DATABASE_URL", "postgres://user:pass@host:5432/my-db")
env := Env{}
ParseEnv(env, &env)
fmt.Println(env)
}
http://play.golang.org/p/b8uPPVo4aV
但是,如您所见,我必须将引用和指针都传递给我的函数。
虽然这有效,但它非常难看(至少我认为是)。
如果我试图只传递指针,我就不能得到正确的类型(因为它将是一个 *interface{}
),而且,如果我只传递引用,我就不能设置值使用 reflect
(即使我可以,它也行不通)。
有没有明智的方法来做到这一点?
下面是一个 "saner" 方法来做你想做的事。您会注意到,我们不需要传入结构的两个副本,而只需要一个指向结构的指针。
func ParseEnv(val interface{}) {
ptrRef := reflect.ValueOf(val)
if ptrRef.Kind() != reflect.Ptr {
panic("pointer to struct expected")
}
ref := ptrRef.Elem()
if ref.Kind() != reflect.Struct {
panic("pointer to struct expected")
}
refType := ref.Type()
for i := 0; i < refType.NumField(); i++ {
field := refType.Field(i)
value := os.Getenv(field.Tag.Get("env"))
if value == "" {
continue
}
ref.Field(i).SetString(value)
}
}
以上函数应按以下方式调用:
ParseEnv(&env)