首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用毒蛇解除hcl到struct

使用毒蛇解除hcl到struct
EN

Stack Overflow用户
提问于 2018-01-13 13:43:56
回答 2查看 3K关注 0票数 2

试图将一个Unmarshal配置文件Unmarshal到一个结构,使用viper返回这个错误:1 error(s) decoding:\n\n* 'NATS' expected a map, got 'slice'。少了什么?

守则:

代码语言:javascript
复制
func lab() {
    var c conf

    // config file
    viper.SetConfigName("draft")
    viper.AddConfigPath(".")
    viper.SetConfigType("hcl")
    if err := viper.ReadInConfig(); err != nil {
        log.Error(err)
        return
    }

    log.Info(viper.Get("NATS")) // gives [map[port:10041 username:cl1 password:__Psw__4433__ http_port:10044]]

    if err := viper.Unmarshal(&c); err != nil {
        log.Error(err)
        return
    }

    log.Infow("got conf", "conf", c)
}

type conf struct {
    NATS struct {
        HTTPPort int
        Port     int
        Username string
        Password string
    }
}

以及配置文件(当前目录中的draft.hcl):

代码语言:javascript
复制
NATS {
    HTTPPort = 10044
    Port     = 10041
    Username = "cl1"
    Password = "__Psw__4433__"
}

编辑

使用hcl包检查了此结构,并正确地封送/解除封送。而且,这对yamlviper也是正确的。

这两种名称为log.Info(viper.Get("NATS"))的地方有区别。当hcl版本返回一个映射片段时,yaml版本返回一个映射:map[password:__psw__4433__ httpport:10044 port:10041 username:cl1]

EN

回答 2

Stack Overflow用户

发布于 2018-01-13 15:05:31

你的结构与HCL不匹配。当转换为json时,HCL如下所示

代码语言:javascript
复制
{
"NATS": [
    {
      "HTTPPort": 10044,
      "Password": "__Psw__4433__",
      "Port": 10041,
      "Username": "cl1"
    }
  ]
}

所以Conf结构应该如下所示

代码语言:javascript
复制
type Conf struct {
    NATS []struct{
        HTTPPort int
        Port     int
        Username string
        Password string
    }
}

修改码

代码语言:javascript
复制
package main
import (
  "log"
  "github.com/spf13/viper"
  "fmt"
)

type Conf struct {
    NATS []struct{
        HTTPPort int
        Port     int
        Username string
        Password string
    }
}

func main() {
    var c Conf
    // config file
    viper.SetConfigName("draft")
    viper.AddConfigPath(".")
    viper.SetConfigType("hcl")
    if err := viper.ReadInConfig(); err != nil {
        log.Fatal(err)
    }
    fmt.Println(viper.Get("NATS")) // gives [map[port:10041 username:cl1 password:__Psw__4433__ http_port:10044]]

    if err := viper.Unmarshal(&c); err != nil {
        log.Fatal(err)
    }
    fmt.Println(c.NATS[0].Username)
}
票数 5
EN

Stack Overflow用户

发布于 2020-06-26 21:29:41

我知道这个问题已经两年多了,但最近我遇到了同样的问题。

我使用viper将不同的配置文件加载到Go结构中,允许在JSON、YAML、TOML、HCL中进行配置,只需选择您最喜欢的:)

HCL文件格式确实将映射包装到片中,因为它允许重新定义如下所示的节:

代码语言:javascript
复制
section = {
  key1 = "value"
}

section = {
  key2 = "value"
}

这是其他格式不支持的东西。

我就是这样修好的:

  • 我的解决方案意味着每一个新的块都将覆盖以前对同一键的任何定义,并保留所有其他的键。你可以做一些合并魔法,但我不需要。
  1. 您需要制作一个钩子来将一段映射转换为一个映射:
代码语言:javascript
复制
// sliceOfMapsToMapHookFunc merges a slice of maps to a map
func sliceOfMapsToMapHookFunc() mapstructure.DecodeHookFunc {
    return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
        if from.Kind() == reflect.Slice && from.Elem().Kind() == reflect.Map && (to.Kind() == reflect.Struct || to.Kind() == reflect.Map) {
            source, ok := data.([]map[string]interface{})
            if !ok {
                return data, nil
            }
            if len(source) == 0 {
                return data, nil
            }
            if len(source) == 1 {
                return source[0], nil
            }
            // flatten the slice into one map
            convert := make(map[string]interface{})
            for _, mapItem := range source {
                for key, value := range mapItem {
                    convert[key] = value
                }
            }
            return convert, nil
        }
        return data, nil
    }
}
  1. 然后您需要创建一个DecodeHook:
代码语言:javascript
复制
configOption := viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
        sliceOfMapsToMapHookFunc(),
        mapstructure.StringToTimeDurationHookFunc(),
        mapstructure.StringToSliceHookFunc(","),
    ))

另外两个钩子是默认的,所以您可能希望保留它们。

然后,将该选项传递给解组方法。

代码语言:javascript
复制
viper.Unmarshal(&c, configOption)

使用这种方法,您不需要在您的结构或映射周围切片。这也使它与其他配置文件格式兼容。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48240461

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档