Essential Go  Suggest an edit

YAML

YAML is a popular format for serializing data in a human friendly format. Think JSON but easier to read.

Thanks to its expressivness and readability, YAML is popular as a format for configuration files.

It’s also used in more complex scenarios like driving Ansible server automation.

There is no package in standard library for hanlding YAML format but there are community libraries including gopkg.in/yaml.v2.

Reading YAML file into a Go struct

dependencies:
  - name: apache
    version: 1.2.3
    repository: http://example.com/charts
  - name: mysql
    version: 3.2.1
    repository: http://another.example.com/charts

// Dependency describes a dependency
type Dependency struct {
	Name          string
	Version       string
	RepositoryURL string `yaml:"repository"`
}

type YAMLFile struct {
	Dependencies []Dependency `yaml:"dependencies"`
}

f, err := os.Open("data.yml")
if err != nil {
	log.Fatalf("os.Open() failed with '%s'\n", err)
}
defer f.Close()

dec := yaml.NewDecoder(f)

var yamlFile YAMLFile
err = dec.Decode(&yamlFile)
if err != nil {
	log.Fatalf("dec.Decode() failed with '%s'\n", err)
}

fmt.Printf("Decoded YAML dependencies: %#v\n", yamlFile.Dependencies)
Decoded YAML dependencies: []main.Dependency{main.Dependency{Name:"apache", Version:"1.2.3", RepositoryURL:"http://example.com/charts"}, main.Dependency{Name:"mysql", Version:"3.2.1", RepositoryURL:"http://another.example.com/charts"}}

YAML decoding is very similar to JSON decoding.

If you know the structure of YAML file, you can define structs that mirror this structure and pass a pointer to a struct describing top-level structure to yaml.Decoder.Decode() function (or yaml.Unmarshal() if decoding from []byte slice).

YAML decoder does intelligent mapping between struct field names and names in YAML file so that e.g. name value in YAML is decoded into field Name in a struct.

It’s best to create explicit mappings using yaml struct tags. I only omitted them from the example to illustrate the behavior when they are not specified.

Writing Go struct to YAML file

type Person struct {
	fullName string
	Name     string
	Age      int    `yaml:"age"`
	City     string `yaml:"city"`
}

p := Person{
	Name: "John",
	Age:  37,
	City: "SF",
}
d, err := yaml.Marshal(&p)
if err != nil {
	log.Fatalf("yaml.Marshal failed with '%s'\n", err)
}
fmt.Printf("Person in YAML:\n%s\n", string(d))
Person in YAML:
name: John
age: 37
city: SF

yaml.Marshal takes interface{} as an argument. You can pass any Go value, it’ll be wrapped into interface{} with their type.

Marshaller will use reflection to inspect passed value and encode it as YAML strings.

When serializing structs, only exported fields (whose names start with capital letter) are serialized / deserialized.

In our example, fullName is not serialized.

Structs are serialized as YAML dictionaries. By default dictionary keys are the same as struct field names.

Struct field Name is serialized under dictionary key Name.

We can provide custom mappings with struct tags.

We can attach arbitrary struct tags string to struct fields.

yaml:"age" instructs YAML encoder / decoder to use name age for dictionary key representing field Age.

When serializing structs, passing the value and a pointer to it generates the same result.

Passing a pointer is more efficient because passing by value creates unnecessary copy.

  ↑ ↓ to navigate     ↵ to select     Esc to close