Skip to content

Instantly share code, notes, and snippets.

@tangx
Created August 7, 2020 22:53
Show Gist options
  • Save tangx/52136a010080daab65283030d8ee8234 to your computer and use it in GitHub Desktop.
Save tangx/52136a010080daab65283030d8ee8234 to your computer and use it in GitHub Desktop.
golang利用反射获取或设置环境变量
package envvar
import (
"encoding/json"
"fmt"
"os"
"reflect"
"strconv"
"strings"
)
// MustUnmarshalFromEnvs Get value form Enviroment
// v must be ptr
// ref: https://www.zhihu.com/question/22783511/answer/24960616
// ref: https://blog.csdn.net/skh2015java/article/details/79292743
func MustUnmarshalFromEnvs(v interface{}, prefix string) {
m := make(map[string]interface{})
// rv := reflect.Indirect(reflect.ValueOf(v))
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
err := fmt.Errorf("want a Struct Ptr , Got a %v", rv.Kind())
panic(err)
}
rvIndirect := reflect.Indirect(rv)
if rvIndirect.Kind() != reflect.Struct {
err := fmt.Errorf("want a Struct Ptr, got a %v", rvIndirect.Kind())
panic(err)
}
typ := rvIndirect.Type()
for i := 0; i < typ.NumField(); i++ {
filed := typ.Field(i)
// spew.Dump(filed)
tag := filed.Tag.Get("env")
envName := fmt.Sprintf("%s_%s", prefix, strings.ToUpper(TagHead(tag)))
envValue := os.Getenv(envName)
switch filed.Type.Kind() {
case reflect.String:
m[filed.Name] = envValue
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
m[filed.Name] = ParseNumber(envValue)
case reflect.Bool:
m[filed.Name] = ParseBool(envValue)
}
}
bBytes, _ := json.Marshal(m)
err := json.Unmarshal(bBytes, v)
if err != nil {
panic(err)
}
}
func TagHead(tag string) string {
l := strings.Split(tag, ",")
return l[0]
}
func ParseBool(s string) bool {
switch strings.ToLower(s) {
case "t", "true":
return true
case "f", "false":
return false
default:
return false
}
}
func ParseNumber(s string) int64 {
n, err := strconv.ParseInt(s, 10, 64)
if err != nil {
// panic(err)
return 0
}
return n
}
package envvar
import (
"os"
"testing"
"github.com/davecgh/go-spew/spew"
. "github.com/smartystreets/goconvey/convey"
)
type Person struct {
Name string `env:"name,omitempty"`
Age int `env:"age,omitempty"`
Gender bool `env:"gender,omitempty"`
}
func Test_MustUnmarshalFromEnv(t *testing.T) {
var p = Person{}
os.Setenv("CI_PROJECT_NAME", "zhangsanfeng")
os.Setenv("CI_PROJECT_AGE", "12")
os.Setenv("CI_PROJECT_GENDER", "false")
MustUnmarshalFromEnvs(&p, "CI_PROJECT")
spew.Dump(p)
Convey("判断环境变量读取结果", t, func() {
So(p.Name, ShouldEqual, "zhangsanfeng")
So(p.Age, ShouldEqual, 12)
So(p.Gender, ShouldBeFalse)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment