Call oneyaml.Marshal on the struct and write the bytes. Fields come out in declaration order, in block style, named by their yaml tags.
mkdir write-yaml && cd write-yaml go mod init example.com/write-yaml go get oneyaml.dev/[email protected]
Put this in main.go and run go run .:
package main import ( "fmt" "log" "os" "reflect" oneyaml "oneyaml.dev/go" ) type Service struct { Name string `yaml:"name"` Image string `yaml:"image"` Replicas int `yaml:"replicas"` Ports []int `yaml:"ports"` Env map[string]string `yaml:"env"` Command []string `yaml:"command,omitempty"` Note string `yaml:"note"` } func main() { svc := Service{ Name: "web", Image: "nginx:1.27", Replicas: 2, Ports: []int{80, 443}, Env: map[string]string{"LOG_LEVEL": "info", "PORT": "8080"}, Note: "no", } out, err := oneyaml.Marshal(svc) if err != nil { log.Fatal(err) } if err := os.WriteFile("service.yaml", out, 0o644); err != nil { log.Fatal(err) } fmt.Print(string(out)) // Read it back: the same value. var back Service if err := oneyaml.Unmarshal(out, &back); err != nil { log.Fatal(err) } fmt.Println("round trip equal:", reflect.DeepEqual(back, svc)) }
name: web image: nginx:1.27 replicas: 2 ports: - 80 - 443 env: LOG_LEVEL: info PORT: '8080' note: 'no' round trip equal: true
command is empty and omitempty leaves it out. Map keys come out sorted. Strings that some reader could take for another type are quoted, so the file means what the struct held for every parser: '8080', and 'no', which unquoted a YAML 1.1 parser such as yaml.v2 would read as false. To stream several documents to a writer, use oneyaml.NewEncoder(w).
Limits
- No comments. A struct has nowhere to keep them. To change a file people maintain by hand and keep its comments, edit it as a
Document: edit YAML and keep its comments. - Map keys are sorted. When the order matters, use a struct, whose fields keep their declaration order.
To read the file into the struct: parse YAML into a struct.