Go Templates

This website is written using Hugo, a static site generator. Hugo, in turn, is written in Go and uses the Go text/template package. So let’s root around in there a bit and see what’s going on.

This will serve as sort of an introduction to Hugo, Go, and the text/template package.

*While writing this, I learned that you should search for golang and not go when browsing the internet.*

Overview

The text/template package uses double curly brackets to replace text in a string. All other text is literally copied over. This is pretty similar to Angular templates or Mustache.js?

Here’s a programmatic example, shamelessly copied from the Go documentation:

type Inventory struct {
	Material string
	Count    uint
}
sweaters := Inventory{"wool", 17}
tmpl, err := template.New("test")
	.Parse("{{.Count}} items are made of {{.Material}}")
if err != nil { panic(err) }
err = tmpl.Execute(os.Stdout, sweaters)
if err != nil { panic(err) }

I see that we have a type keyword, we define an Inventory and I think it’s a struct (whatever that means).

Looks awfully similar to a template in Typescript. My C/C++ is pretty weak, but I’d imagine that a Go struct is similar. Something like data without behavior. If it had behavior it would be a so-called “class”.

The Goverview

Welcome to the Thundergome?

I’m going to dig in to all of the words I don’t know about. Lucky you.

Type declarations

We used the type keyword to create a type declaration for the Inventory type, which is a struct. Type declarations can be either an alias declaration or a type definition. Let’s look at the type definition We’ll concern ourselves just with the type declarations.

A type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it.

In our example from the go documentation, we created a new type with the same underlying type as a struct and with the identifier Inventory.

Go structs

Go structs are collections of fields – data without behavior. Some initial reading shows that Go does not have classes – I wonder if structs support inheritance, or attaching methods to the struct?

Assignment

The := operator looks like crazy assignment. We don’t need a declaration keyword or a declared type, which is nice. I hear a lot of people are using Go at the enterprise so I bet it’s not very weakly typed – maybe uses something like duck-typing in Python.

Wikipedia says that Go uses structural typing so I’m not sure what that means yet. It looks like duck typing is a looser form of typing, where only the parts of the type that are accessed are actually checked. In structural typing the entire structure needs to match.

I wonder if Python is actually duck typed?

Turns out, := is crazy assignment, it’s a short variable declaration.

These are all equivalent:

var a int = 10
var a = 10
a := 10

Tuple assignment

The assignment of temp, err is a tuple assignment and follows some rules.

Which means that template.new("test") returns multiple values, the resulting string and a possible error.

The nil value

In Go, nil is the zero value for pointers, interfaces, maps, slices, channels and function types, representing an uninitialized value.

Panicking

The built-in function panic is how Go does error handling. I’m so into that.

The os package

Go provides a wrapper around operating system functionality in the os package. It’s supposed to be platform indepenedent so it should work on Windows, Mac, and GNU+Linux.

Stdout means the standard out file descriptor. I’ve never taken an Operating Systems course, so I don’t actually know what a “file descriptor” is.

text/template

Now that we know everything about Go, we can dig into the text/template package some more.

Trimming

We can trim whitespace around operators using the - sign:

"{{34 -}} > {{- 26}}" // "34>26"
"{{34}} > {{26}}" // "34 > 26"
"{{34-}} > {{-26}}" // "34- > -26"

Data driven

Go templates are data-driven templates producing textual output. We define the data in, the template data, and get string data out. Instead of procedurally defining how things should be layed out. So, we declare a data structure, define properties on it, pass that to a template definition, then receive a string output.

This is only sort of true, since we do have some imperative/procedural statements.

Keywords:

Here are some built in functions to use as pipelines:

Boolean functions:

You can nest templates, so a template definition can contain other template invocations(?) Again, copied from the documentation:

`{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}`