package env import ( "reflect" "strings" "strconv" "os" "fmt" "time" ) var ( DEFAULT_SEPARATOR = "_" ) func upper(v string) string { return strings.ToUpper(v) } func Fill(v interface{}) error { if reflect.ValueOf(v).Kind() != reflect.Ptr { return fmt.Errorf("env.Fill 只接受指针类型的值") } ind := reflect.Indirect(reflect.ValueOf(v)) prefix := upper(ind.Type().Name()) err := fill(prefix, ind) if err != nil { return err } return nil } func combine(p, n string, v string, ok bool) string{ if !ok { return p + DEFAULT_SEPARATOR + n } return p + v + n } func parseBool(v string) (bool, error) { if v == "" { return false, nil } return strconv.ParseBool(v) } func fill(pf string, ind reflect.Value) error{ for i := 0; i < ind.NumField(); i++ { f := ind.Type().Field(i) name := f.Name envName, exist := f.Tag.Lookup("env") if exist { name = envName } s, exist := f.Tag.Lookup("sep") p := combine(pf, upper(name), s, exist) switch ind.Field(i).Kind() { case reflect.Struct: err := fill(p, ind.Field(i)) if err != nil { return err } default: err := parse(p, ind.Field(i), f) if err != nil { return err } } } return nil } func parse(prefix string, f reflect.Value, sf reflect.StructField) error { //log.Print("parse:", prefix, f.String(), f.Type().String(), f.Kind().String()) df := sf.Tag.Get("default") isRequire, err := parseBool(sf.Tag.Get("require")) if err != nil { return fmt.Errorf("字段:%s require不是合法的布尔值,支持: 1 t T true TRUE True.", prefix) } ev, exist := os.LookupEnv(prefix) if !exist && isRequire { return fmt.Errorf("%s 是必须的变量,但没有被设置", prefix) } if !exist && df != "" { ev = df } //log.Print("ev:", ev) switch f.Kind() { case reflect.String: f.SetString(ev) case reflect.Int: iv, err := strconv.ParseInt(ev, 10, 32) if err != nil { return err } f.SetInt(iv) case reflect.Int64: if f.Type().String() == "time.Duration" { t, err := time.ParseDuration(ev) if err != nil { return err } f.Set(reflect.ValueOf(t)) } else { iv, err := strconv.ParseInt(ev, 10, 64) if err != nil { return err } f.SetInt(iv) } case reflect.Uint: uiv, err := strconv.ParseUint(ev, 10, 32) if err != nil { return err } f.SetUint(uiv) case reflect.Uint64: uiv, err := strconv.ParseUint(ev, 10, 64) if err != nil { return err } f.SetUint(uiv) case reflect.Float32: f32, err := strconv.ParseFloat(ev, 32) if err != nil { return err } f.SetFloat(f32) case reflect.Float64: f64, err := strconv.ParseFloat(ev, 64) if err != nil { return err } f.SetFloat(f64) case reflect.Bool: b, err := parseBool(ev) if err != nil { return err } f.SetBool(b) case reflect.Slice: sep := ";" s, exist := sf.Tag.Lookup("slice_sep") if exist && s != "" { sep = s } vals := strings.Split(ev, sep) switch f.Type() { case reflect.TypeOf([]string{}): f.Set(reflect.ValueOf(vals)) case reflect.TypeOf([]int{}): t := make([]int, len(vals)) for i, v := range vals { val, err := strconv.ParseInt(v, 10, 32) if err != nil { return err } t[i] = int(val) } case reflect.TypeOf([]int64{}): t := make([]int64, len(vals)) for i, v := range vals { val, err := strconv.ParseInt(v, 10, 64) if err != nil { return err } t[i] = val } case reflect.TypeOf([]uint{}): t := make([]uint, len(vals)) for i, v := range vals { val, err := strconv.ParseUint(v, 10, 32) if err != nil { return err } t[i] = uint(val) } case reflect.TypeOf([]uint64{}): t := make([]uint64, len(vals)) for i, v := range vals { val, err := strconv.ParseUint(v, 10, 64) if err != nil { return err } t[i] = val } case reflect.TypeOf([]float32{}): t := make([]float32, len(vals)) for i, v := range vals { val, err := strconv.ParseFloat(v, 32) if err != nil { return err } t[i] = float32(val) } case reflect.TypeOf([]float64{}): t := make([]float64, len(vals)) for i, v := range vals { val, err := strconv.ParseFloat(v, 64) if err != nil { return err } t[i] = val } case reflect.TypeOf([]bool{}): t := make([]bool, len(vals)) for i, v := range vals { val, err := parseBool(v) if err != nil { return err } t[i] = val } } } return nil }