使用 viper 解组 hcl 以进行结构化

Kav*_*ian 2 configuration go viper-go

尝试Unmarshal一个hcl配置文件的结构,使用viper,返回此错误:1 error(s) decoding:\n\n* 'NATS' expected a map, got 'slice'。有什么不见了?

编码:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

和配置文件(draft.hcl在当前目录内):

NATS {
    HTTPPort = 10044
    Port     = 10041
    Username = "cl1"
    Password = "__Psw__4433__"
}
Run Code Online (Sandbox Code Playgroud)

编辑

已经用hcl包检查了这个结构,它被正确地编组/解组。这也适用于yamlviper

这两者之间有一个区别 wherelog.Info(viper.Get("NATS"))被称为。虽然hcl版本返回地图切片,该yaml版本会返回地图:map[password:__psw__4433__ httpport:10044 port:10041 username:cl1]

Anu*_*dha 5

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

{
"NATS": [
    {
      "HTTPPort": 10044,
      "Password": "__Psw__4433__",
      "Port": 10041,
      "Username": "cl1"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

所以Conf结构应该是这样的

type Conf struct {
    NATS []struct{
        HTTPPort int
        Port     int
        Username string
        Password string
    }
}
Run Code Online (Sandbox Code Playgroud)

修改代码

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)
}
Run Code Online (Sandbox Code Playgroud)