Elide type in composite literals in Golang

Composite types are containers for other values. In Golang composite types are arrays, slices, maps and structs. Composite literals specify elements of composite types. Optional key can be placed before each element. For maps that key is required. Let’s see all four types in action (source code):

type T struct {
foo int64
bar int64
}
func main() {
_ = map[string]int64{"foo": 1, "bar": 2}
_ = [3]int64{1, 2, 3}
_ = [3]int64{1: 1, 2: 2}
_ = []int{1, 2, 3}
_ = []int{1: 1, 2: 2}
_ = T{foo: 1, bar: 2}
_ = T{1, 2}
}

Key for slice or array must be a non-negative integer constant. For array additionally within allowed range [0, len — 1]:

_ = [3]int64{4: 4}

Gives array index 4 out of bounds [0:3] while building.

One less know feature of the language is the possibility to omit type of elements or map keys (source code):

type T struct {
foo string
bar int64
}
func main() {
_ = []T{{"a", 1}, {"b", 2}, {"c", 3}}
}

The longer version of such composite literal is:

_ = []T{T{"a", 1}, T{"b", 2}, T{"c", 3}}

It requires less typing plus the code is more compact and readable. Let’s see where exactly this option is applicable…


Arrays & Slices

(source code)

type T struct {
f string
}
func main() {
v1 := [...]T{{"foo"}, {"bar"}}
fmt.Printf("%#v\n", v1)
v2 := [2]T{{"foo"}, {"bar"}}
fmt.Printf("%#v\n", v2)
v3 := []T{{"foo"}, {"bar"}}
fmt.Printf("%#v\n", v3)
}

Output:

[2]main.T{main.T{f:"foo"}, main.T{f:"bar"}}
[2]main.T{main.T{f:"foo"}, main.T{f:"bar"}}
[]main.T{main.T{f:"foo"}, main.T{f:"bar"}}

The whole mechanism works also for multi-dimensional elements (source code):

type T struct {
f int
}
func main() {
v1 := [2][2]T{{{1}, {2}}, {{3}, {4}}}
fmt.Printf("%#v\n", v1)
v2 := [][]int{{1, 2}, {3}}
fmt.Printf("%#v\n", v2)
}

output:

[2][2]main.T{[2]main.T{main.T{f:1}, main.T{f:2}}, [2]main.T{main.T{f:3}, main.T{f:4}}}
[][]int{[]int{1, 2}, []int{3}}

Full version of the first composite literal is way less readable:

[2][2]T{[2]T{T{1}, T{2}}, [2]T{T{3}, T{4}}}

Maps

(source code)

type T struct {
f string
}
func main() {
v1 := map[string]T{"foo": {"bar"}}
fmt.Printf("%#v\n", v1)
v2 := map[T]string{{"foo"}: "bar"}
fmt.Printf("%#v\n", v2)
v3 := map[T]T{{"foo"}: {"bar"}}
fmt.Printf("%#v\n", v3)
}

output:

map[string]main.T{"foo":main.T{f:"bar"}}
map[main.T]string{main.T{f:"foo"}:"bar"}
map[main.T]main.T{main.T{f:"foo"}:main.T{f:"bar"}}

Pointers

If type of element or key is a pointer (*T) then inside composite literal it’s valid to omit &T (source code):

type T struct {
f string
}
func main() {
v1 := map[string]*T{"foo": {"bar"}}
fmt.Printf("%#v\n", v1)
v2 := [...]*T{{"foo"}, {"bar"}}
fmt.Printf("%#v\n", v2)
v3 := []*T{{"foo"}, {"bar"}}
fmt.Printf("%#v\n", v3)
}

output:

map[string]*main.T{"foo":(*main.T)(0x1040c108)}
[2]*main.T{(*main.T)(0x1040c120), (*main.T)(0x1040c128)}
[]*main.T{(*main.T)(0x1040c140), (*main.T)(0x1040c148)}

Struct

When it goes to struct types then omitting field type is not possible. First of all it isn’t possible to create nested structures (source code):

type T struct {
name string
next T
}

as it triggers an error while compilation:

invalid recursive type T

It’s possible though in struct of type T to have a field o type *T (source code):

type T struct {
name string
next *T
}
func main() {
_ = T{"foo", &T{"bar", nil}}
_ = T{"foo", {"bar", nil}}
}

2nd assignment causes anyway compile-time error missing type in composite literal.