当 yaml 已经初始化值时,如何在 Golang 中测试默认值?

rob*_*nes 1 go

我正在编写守护程序的配置处理程序并利用该yaml包来执行此操作。导入我的文件的工作方式如下:

package daemon

import (
    "ioutil"
    "log"

    "gopkg.in/yaml.v2"
)

type daemonConfig struct {
    BindAddress string `yaml:"bind_address"`
    BindPort    int    `yaml:"bind_port"`
    VerifySSL   bool   `yaml:"verify_ssl"`
}
Run Code Online (Sandbox Code Playgroud)

我可以轻松地从 YAML 文件中解组数据,如下所示:

func (config *daemonConfig) getConf() *daemonConfig {
    yamlFile, err := ioutil.ReadFile("config.yaml")
    if err != nil {
        log.Fatal("Unable to open config.yaml:", err)
    }
    err = yaml.Unmarshal(yamlFile, config)
    if err != nil {
        log.Fatal("Failed to unmarshall config.yaml:", err)
    }
    config, err = setDefaults(config)

    return config
}
Run Code Online (Sandbox Code Playgroud)

我的问题是关于我的自定义 setDefaults 函数。如果未提供字段,例如bind_portbind_address,我只想将它们设置为默认值:

func setDefaults(config *daemonConfig) (*daemonConfig, error) {
    if len(config.BindAddress) <= 0 {
        config.BindAddress = "0.0.0.0"
    }
    if config.BindPort == 0 {
        config.BindPort = 9999
    }

    return config, nil
}
Run Code Online (Sandbox Code Playgroud)

您会注意到我没有将默认值设置为verify_ssl; 当yaml解组它并且找不到该字段时,它会初始化boolas false,这与我想要的默认行为正好相反。我希望用户明确地将 SSL 验证设置为关闭,而不是在未指定的情况下默认关闭。如果我有一个完全空的config.yaml,并期望设置默认值,它将始终设置verify_ssl为 false(此日志来自应用程序的其他地方):

2019/02/19 03:56:08 Currently loaded config: {0.0.0.0 9999 false}
Run Code Online (Sandbox Code Playgroud)

如果正在解组的 YAML 字段中不存在此字段,我将如何检查该行是否存在?我可以手动读取文件并首先检查该参数,但我想知道是否有更优雅的方法;否则,我将只使用ioutil和字符串检查来做到这一点。谢谢!

rob*_*nes 5

感谢Thomasmh-cbon,我发现我可以为此使用指针。如果我更改我的VerifySSL字段以使用指针并添加omitempty

type daemonConfig struct {
    BindAddress string `yaml:"bind_address"`
    BindPort    int    `yaml:"bind_port"`
    VerifySSL   *bool  `yaml:"verify_ssl",omitempty`
}
Run Code Online (Sandbox Code Playgroud)

我可以简单地取消引用结构中的字段以获得yaml解组内容的真实值。设置默认值非常简单:

func setDefaults(config *daemonConfig) (*daemonConfig, error) {
    if len(config.BindAddress) <= 0 {
        config.BindAddress = "0.0.0.0"
    }
    if config.BindPort == 0 {
        config.BindPort = 9999
    }
    if config.VerifySSL == nil {
        ssl := true
        config.VerifySSL = &ssl
    }

    return config, nil
}
Run Code Online (Sandbox Code Playgroud)

如果它被加载到文件中,config.VerifySSL将包含 的地址bool,所以它不会是nil,如果它真的根本不在文件中,那么该字段很简单nil,我可以设置它或通过指针获取它。

编辑:请注意,如果您的VerifySSL指针为零,则不能像这样分配它:

*config.VerifySSL = true
Run Code Online (Sandbox Code Playgroud)

那就是取消引用一个nil指针。我已经更新了解决方案以包含更易于管理的内容。