反映:设置指针的字段

时间:2015-07-29 02:16:32

标签: pointers reflection go

我试图做这样的事情:

使用名为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的值(即使我可以,它也不起作用)。

有没有理智的做法?

1 个答案:

答案 0 :(得分:4)

以下是&#34; saner&#34;做你想做的事。您会注意到,我们只需要一个指向结构的指针,而不是传入结构的两个副本。

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)

示例:https://play.golang.org/p/_BwWz2oUql