package confm import ( "errors" "gopkg.in/yaml.v3" "log" "os" "strconv" "strings" ) //变量 //实例池 var pool = map[string]*config{} //默认选项值 var optionDefault = Option{ Path: "./configs/", Ext: ".yml", Sep: ".", } //类型 //配置内容 type contents = map[string]map[string]interface{} type config struct { option Option //配置文件内容解码缓存 contents } type Option struct { Name string Path string Ext string Sep string } // New 创建对象 func New(option ...Option) *config { verifiedOption := optionVerify(option...) return create(verifiedOption) } // Get 存在直接返回,否则创建、存储再返回 func Get(option ...Option) *config { verifiedOption := optionVerify(option...) if !Has(verifiedOption.Name) { pool[verifiedOption.Name] = create(verifiedOption) } return pool[verifiedOption.Name] } // Has 存在返回 true,否则返回 false func Has(name string) bool { _, has := pool[name] return has } func create(option Option) *config { return &config{ option: option, contents: contents{}, } } func optionVerify(option ...Option) Option { opt := optionDefault if len(option) > 0 { opt.Name = option[0].Name if option[0].Path != "" { opt.Path = option[0].Path } if option[0].Ext != "" { opt.Ext = option[0].Ext if !strings.HasPrefix(opt.Ext, ".") { opt.Ext = "." + opt.Ext } } if option[0].Sep != "" { opt.Sep = option[0].Sep } } return opt } //可导出包方法 // Bool Getter|Setter func (c config) Bool(key string) bool { valueIf, err := c.value(key) if err != nil { return false } value, ok := valueIf.(bool) if !ok { return false } return value } func (c config) String(key string) string { valueIf, err := c.value(key) if err != nil { return "" } return assertString(valueIf) } func (c config) Int(key string) int { valueIf, err := c.value(key) if err != nil { log.Println(err) return 0 } value, ok := valueIf.(int) if !ok { return 0 } return value } func (c config) Uint(key string) uint { valueIf, err := c.value(key) if err != nil { log.Println(err) return 0 } value, ok := valueIf.(uint) if !ok { return 0 } return value } func (c config) Float64(key string) float64 { valueIf, err := c.value(key) if err != nil { return 0 } return assertFloat64(valueIf) } func (c config) Float32(key string) float32 { valueIf, err := c.value(key) if err != nil { return 0 } return assertFloat32(valueIf) } func (c config) BoolSlice(key string) []bool { valueIf, err := c.value(key) if err != nil { return []bool{} } // sli, ok := valueIf.([]interface{}) if !ok { return []bool{} } value := make([]bool, len(sli)) for i, vi := range sli { v, ok := vi.(bool) if ok { value[i] = v } } return value } func (c config) IntSlice(key string) []int { valueIf, err := c.value(key) if err != nil { return []int{} } // sli, ok := valueIf.([]interface{}) if !ok { return []int{} } value := make([]int, len(sli)) for i, vi := range sli { v, ok := vi.(int) if ok { value[i] = v } } return value } func (c config) StringSlice(key string) []string { valueIf, err := c.value(key) if err != nil { return []string{} } // sli, ok := valueIf.([]interface{}) if !ok { return []string{} } value := make([]string, len(sli)) for i, vi := range sli { value[i] = assertString(vi) } return value } func (c config) Float64Slice(key string) []float64 { valueIf, err := c.value(key) if err != nil { return []float64{} } // sli, ok := valueIf.([]interface{}) if !ok { return []float64{} } value := make([]float64, len(sli)) for i, vi := range sli { value[i] = assertFloat64(vi) } return value } func (c config) Float32Slice(key string) []float32 { valueIf, err := c.value(key) if err != nil { return []float32{} } // sli, ok := valueIf.([]interface{}) if !ok { return []float32{} } value := make([]float32, len(sli)) for i, vi := range sli { value[i] = assertFloat32(vi) } return value } func (c config) BoolMap(key string) map[string]bool { valueIf, err := c.value(key) if err != nil { return map[string]bool{} } // mp, ok := valueIf.(map[string]interface{}) if !ok { return map[string]bool{} } value := map[string]bool{} for k, vk := range mp { value[k] = false v, ok := vk.(bool) if ok { value[k] = v } } return value } func (c config) IntMap(key string) map[string]int { valueIf, err := c.value(key) if err != nil { return map[string]int{} } // mp, ok := valueIf.(map[string]interface{}) if !ok { return map[string]int{} } value := map[string]int{} for k, vk := range mp { value[k] = 0 v, ok := vk.(int) if ok { value[k] = v } } return value } func (c config) Float64Map(key string) map[string]float64 { valueIf, err := c.value(key) if err != nil { return map[string]float64{} } // mp, ok := valueIf.(map[string]interface{}) if !ok { return map[string]float64{} } value := map[string]float64{} for k, vk := range mp { value[k] = assertFloat64(vk) } return value } func (c config) Float32Map(key string) map[string]float32 { valueIf, err := c.value(key) if err != nil { return map[string]float32{} } // mp, ok := valueIf.(map[string]interface{}) if !ok { return map[string]float32{} } value := map[string]float32{} for k, vk := range mp { value[k] = assertFloat32(vk) } return value } func (c config) StringMap(key string) map[string]string { valueIf, err := c.value(key) if err != nil { return map[string]string{} } // mp, ok := valueIf.(map[string]interface{}) if !ok { return map[string]string{} } value := map[string]string{} for k, vk := range mp { value[k] = assertString(vk) } return value } //非导出方法 //利用 key 获取 值 func (c config) value(key string) (interface{}, error) { filename, keys := c.parseKey(key) if data, exists := c.contents[filename]; !exists { var ( content = []byte{} err error ) if content, err = c.getContent(filename); err != nil { log.Println(err) return nil, err } if err = yaml.Unmarshal(content, &data); err != nil { log.Println(err) return nil, err } c.contents[filename] = data } //解析 for i, l, currLevel := 0, len(keys), c.contents[filename]; i < l; i++ { //最后一级 key if i == l-1 { if value, exists := currLevel[keys[i]]; exists { return value, nil } else { return nil, errors.New("key is not exists") } } //不是最后一级,继续解析 var exists bool currLevel, exists = currLevel[keys[i]].(map[string]interface{}) if !exists { return nil, errors.New("key is not exists") } } return nil, nil } //解析 key func (c config) parseKey(key string) (string, []string) { strs := strings.Split(key, c.option.Sep) if len(strs) == 1 { strs = append([]string{"app"}, strs...) } return strs[0], strs[1:] } //读取配置文件 func (c config) getContent(filename string) ([]byte, error) { return os.ReadFile(c.option.Path + filename + c.option.Ext) } //断言 Interface{} to string func assertString(valueIf interface{}) (value string) { switch v := valueIf.(type) { case string: value = v case int: value = strconv.FormatInt(int64(v), 10) //string(v) case float64: value = strconv.FormatFloat(v, 'f', -1, 64) case float32: value = strconv.FormatFloat(float64(v), 'f', -1, 64) case bool: value = strconv.FormatBool(v) } return } //断言 Interface{} to float32 func assertFloat32(valueIf interface{}) (value float32) { switch v := valueIf.(type) { case float64: value = float32(v) case float32: value = v case int: value = float32(v) } return } //断言 Interface{} to float64 func assertFloat64(valueIf interface{}) (value float64) { switch v := valueIf.(type) { case float64: value = v case float32: value = float64(v) case int: value = float64(v) } return }