How does the Dictionary function in collections.go work?

I’m working on this issue, so I came across the Dictionary function (/tpl/collections/collections.go). Curious about a couple of things:

// Dictionary creates a map[string]interface{} from the given parameters by
// walking the parameters and treating them as key-value pairs.  The number
// of parameters must be even.
// The keys can be string slices, which will create the needed nested structure.
func (ns *Namespace) Dictionary(values ...interface{}) (map[string]interface{}, error) {
	if len(values)%2 != 0 {
		return nil, errors.New("invalid dictionary call")

	root := make(map[string]interface{})

	for i := 0; i < len(values); i += 2 {
		dict := root
		var key string
		switch v := values[i].(type) {
		case string:
			key = v
		case []string:
			for i := 0; i < len(v)-1; i++ {
				key = v[i]
				var m map[string]interface{}
				v, found := dict[key]
				if found {
					m = v.(map[string]interface{})
				} else {
					m = make(map[string]interface{})
					dict[key] = m
				dict = m
			key = v[len(v)-1]
			return nil, errors.New("invalid dictionary key")
		dict[key] = values[i+1]

	return root, nil
  • ...interface{} means that all the values given as arguments would be held in a single interface, correct? I believe this is known as a variadic function. What is it called when I do something like params... that expands the contents of the slice, if I’m saying that correctly?
  • This function is used in the Querify function, which takes a set of key-value pairs and returns a query string that can be appended to a URL. The dictionary function can take a string slice as a key. How does this convert to a query string? I looked at the examples in the tests, but did not understand. One such example:
[]string{"a", "b"}, "c"}, map[string]interface{}{"a": map[string]interface{}{"b": "c"}}

How would this map be represented as a query string?

  • What does m = v.(map[string]interface{}) do?

I’m blurry about some other details as well, but these questions may help me understand them better.


Before I get to your questions, It sounds like you’re familiar with programming, but new to Go. I would highly recommend that you read the entire Go spec. It’s not that long, and the Go language is intentionally simple. If it were any other language, I wouldn’t recommend this to a newbie, but it really helped me understand Go quickly when I was getting started. A little time spent reading the spec will make your programming time more fruitful.

Variadic parameters (p ...T) means we will accept zero or more parameters of type T. They will be presented as a slice to your function. So, in this example, values is a []interface{} inside Dictionary. An interface{} is Go’s way of storing unknown types.

It’s a way to pass a slice as the variadic parameter. You can think of it as slice expansion.

That’s a good question. The Dictionary tests are a little confusing to me, too. I’ll have to take a closer look, but you’ll generally be dealing with the simple examples with Querify.

That is a type assertion. Done incorrectly can cause a panic, so be careful with these.

Further reading in the Go spec:

1 Like

In reply to your questions in GH:

I would only update files relevant to what you’re doing. You don’t have to use mage during dev work. I usually just use the go tool chain.

Querify only needs a subset of what Dictionary is doing, so I wouldn’t worry about extending it to support strings slices as keys. That’s doesn’t really make sense for Querify.

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.