YAML
gopkg.in/yaml.v3 在 Unmarshal 时设置默认值
使用 gopkg.in/yaml.v3 解析 yaml 文件时,我们可以实现结构体的 UnmarshalYAML 接口
在 UnmarshalYAML
方法中,既可以在结构体创建的时候指定默认值,也可以在结构体 Decode 完成之后,设置更复杂的默认值
- test.yaml
application: snowave
runtime: golang
services:
- interface: linaewen.fdoulist
handler: services/api/thrift.go
type: thrift
use_services:
- app: fm
type: grpc
version: 6b15b80
- app: music
version: e89b497be9ef0fb932d5e543ed866f920780750f
- app: pony
version: c5b2e21
- main.go
package main
import (
"fmt"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
"log"
"os"
"strings"
)
type UseService struct {
App string `yaml:"app,omitempty"`
Type string `yaml:"type,omitempty"`
Version string `yaml:"version"`
}
// UnmarshalYAML
//
// 此程序演示了,在 Decode 之前设置 Type 字段的默认值为 thrift
func (u *UseService) UnmarshalYAML(value *yaml.Node) error {
type tmp UseService
ru := tmp{
Type: "thrift",
}
err := value.Decode(&ru)
if err != nil {
return errors.Wrap(err, "UseService: failed to unmarshal")
}
*u = UseService(ru)
return nil
}
type Service struct {
Name string `yaml:"name"`
Interface string `yaml:"interface"`
Type string `yaml:"type"`
Handler string `yaml:"handler"`
}
// UnmarshalYAML
//
// 此函数演示了更复杂的情况, Name 字段的默认值是根据 Interface 的值来设置的
//
// Name 是 Interface 中 `.` 分割的最后一段
// 如果 Interface 中没有 `.` , 则 Name == Interface
func (s *Service) UnmarshalYAML(value *yaml.Node) error {
type tmp Service
rs := tmp{}
err := value.Decode(&rs)
if err != nil {
return errors.Wrap(err, "Service: failed to unmarshal")
}
if rs.Name == "" {
// 注意这里,无论 rs.Interface 的值是什么, tokens 的长度一定 >= 1,
// 所以 tokens[len(tokens)-1] 不会 Panic
tokens := strings.Split(rs.Interface, ".")
rs.Name = tokens[len(tokens)-1]
}
*s = Service(rs)
return nil
}
type AppConfig struct {
Application string `yaml:"application"`
Runtime string `yaml:"runtime"`
Services []*Service `yaml:"services"`
UseServices []*UseService `yaml:"use_services"`
}
func main() {
config := &AppConfig{}
content, _ := os.ReadFile("test.yaml")
err := yaml.Unmarshal(content, config)
if err != nil {
log.Fatalln(err)
}
// 输出
//fdoulist linaewen.fdoulist
for _, svc := range config.Services {
fmt.Println(svc.Name, svc.Interface)
}
// 输出
//fm grpc
//music thrift
//pony thrift
for _, svc := range config.UseServices {
fmt.Println(svc.App, svc.Type)
}
}
参考链接
2023年08月15日 / 11:48