Earlier this year, near the beginning of this series on the Go spec, we went through literal representations of all of the basic types in Go: int
s, string
s, etc.
If this were an Intro to Go style book, the very next section would have been on composite literals. But it’s not. So we had to wait nearly 6 months to get to that topic… But here we are, at long last!
Composite literals
Composite literals construct new composite values each time they are evaluated. They consist of the type of the literal followed by a brace-bound list of elements. Each element may optionally be preceded by a corresponding key.
CompositeLit = LiteralType LiteralValue . LiteralType = StructType | ArrayType | "[" "..." "]" ElementType | SliceType | MapType | TypeName [ TypeArgs ] . LiteralValue = "{" [ ElementList [ "," ] ] "}" . ElementList = KeyedElement { "," KeyedElement } . KeyedElement = [ Key ":" ] Element . Key = FieldName | Expression | LiteralValue . FieldName = identifier . Element = Expression | LiteralValue .
The LiteralType’s core type
T
must be a struct, array, slice, or map type (the syntax enforces this constraint except when the type is given as a TypeName).
So here we have the technical definition of a composite literal, and the more human readable explanation: A composite literal in Go is an expression that evaluates to a composite value. A composite value, in turn, is a type with a core type of struct, array, slice, or map.
There’s one caveat here, mentioned in parenthesis. When we’re using a composite type directly, the syntax itself enforces compliance with this rule.
var x = map[string]string{"a": "b"}
The ambiguity arises when using named types:
type Foo map[string]string
type Bar int
var x = Foo{"a": "b"} // Completely valid
var y = Bar{"a": "b"} // Syntactically valid, but logically incorrect, because named type Bar does not have a composite core type.
Quotes from The Go Programming Language Specification Version of August 2, 2023