Struct Literals
Create and initialize struct values in Go using positional and keyed struct literals, including nested literals and field type elision.
A struct literal is a piece of Go syntax that directly writes out a struct value — fields and all — right where you need it. The compiler reads it and builds the struct in memory in one shot, rather than requiring you to declare a variable and set each field one line at a time. Every time a struct literal is evaluated, it creates a fresh copy of the struct value.
The formal name for this syntax is a composite literal, because it constructs composite types: structs, arrays, slices, and maps. When you see curly braces after a type name — Person{...} — that is a struct literal.
Positional Struct Literals
In a positional literal, you supply a value for every field in the order the fields were declared. You do not write any field names.
type Point struct {
X int
Y int
}
p := Point{10, 20}
This creates a Point with X = 10 and Y = 20. The values map positionally: the first value inside the braces goes to the first field, the second value to the second field.
Positional literals are compact. They work well for small structs with an obvious, stable field order — a 2D point, a complex number, a rectangle. The order is part of the struct’s public contract, so the reader must know it or look it up.
Order is fragile:
If someone adds a new field to the struct definition — especially between existing fields — every positional literal breaks at compile time because the number of values must match exactly. Keyed literals do not have this problem.
You cannot skip a field in a positional literal. If the struct has three fields, you must provide three values. Even if you want the zero value for the middle field, you have to write it explicitly.
type Person struct {
Name string
Age int
City string
}
// Valid positional literal — all three fields populated.
p1 := Person{"Maria", 28, "Lisbon"}
// Compile error: too few values in Person literal
// p2 := Person{"Carlos", 35}
Keyed Struct Literals
A keyed literal uses FieldName: value pairs. You can list the fields in any order, and you may omit fields entirely. Omitted fields are set to their zero value automatically.
p := Person{
City: "Lisbon",
Name: "Maria",
}
Here Age is omitted, so it becomes 0. The order inside the braces does not matter — the compiler matches each key to the corresponding struct field.
Keyed literals make initialization self-documenting. Someone reading the code doesn’t need to check the struct definition to understand which value belongs to which field. This becomes especially valuable when a struct has many fields or when the initialization sits far away from the type definition.
type ServerConfig struct {
Host string
Port int
ReadTimeout time.Duration
WriteTimeout time.Duration
MaxConnections int
TLSEnabled bool
}
config := ServerConfig{
Host: "localhost",
Port: 8080,
ReadTimeout: 5 * time.Second,
MaxConnections: 100,
}
The two omitted fields — WriteTimeout and TLSEnabled — get the zero values 0 and false, which are sensible defaults in this context.
Prefer keyed literals for maintainability:
Keyed literals survive field reorderings and new field insertions without breaking. They also make the intent of each value explicit, which reduces review friction. Use positional literals sparingly — only when the field order is obvious and unlikely to change, like a small geometry type.
Mixing Positional and Keyed Syntax
A single struct literal must commit to one style. You cannot supply some values positionally and others with keys.
// Compile error: mixture of field:value and value initializers
// p := Person{Name: "Maria", 28, City: "Lisbon"}
If the first element uses a key, every element must use a key. If you omit all keys, you must provide a value for every field, in the declared order.
Mixed literals always fail:
The compiler rejects this immediately. There is no scenario where mixing positional and keyed elements inside the same struct literal is valid Go.
Nested Struct Literals
When a struct field is itself a struct, you initialize it with another struct literal nested inside the outer one.
type Address struct {
Street string
City string
}
type Employee struct {
Name string
Address Address
}
e := Employee{
Name: "Henrik",
Address: Address{
Street: "Karl Johans gate 12",
City: "Oslo",
},
}
The inner literal Address{...} is fully explicit. But Go also allows you to elide the inner type name when the field’s type is unambiguous — the compiler already knows the field is of type Address.
Eliding the Type Name in Nested Literals
Since the field Address is declared as type Address, you can drop the type name and write only the braces with their values.
e := Employee{
Name: "Henrik",
Address: {
Street: "Karl Johans gate 12",
City: "Oslo",
},
}
The {...} after Address: is interpreted as an Address struct literal. This works with both keyed and positional syntax inside the nested literal, though using keys is safer.
The same elision applies to slices and arrays of structs.
type Project struct {
Name string
Members []Employee
}
p := Project{
Name: "Apollo",
Members: []Employee{
{Name: "Henrik", Address: {Street: "Gate 12", City: "Oslo"}},
{Name: "Freya", Address: {Street: "Vesterbrogade 37", City: "Copenhagen"}},
},
}
Inside the slice literal, each {...} becomes an Employee because the element type of Members is []Employee. This removes visual noise when initializing deeply nested data, but it comes with a readability trade-off: the reader must know or infer the elided type from context. Use the explicit type name when the meaning would otherwise be unclear.
Elision is inference, not syntax sugar for keys:
Type elision in nested literals only removes the outer type name. You still write field names and values as usual. It does not allow you to omit the field keys of the inner struct unless you also shift to a positional style for that inner literal — but the same rules apply: positional requires all fields in order.
Pointers from Struct Literals
You can prefix a struct literal with & to get a pointer to the newly created value. This is not a special pointer literal; it’s the address operator applied to a composite literal, which Go explicitly allows.
cfg := &ServerConfig{
Host: "api.example.com",
Port: 443,
}
// cfg has type *ServerConfig
This is equivalent to creating the value, then taking its address, but the &T{...} form is idiomatic and common. There is no separate allocation step and no explicit new call required.
Common Mistakes with Struct Literals
Missing trailing comma in multi-line literals. Go requires a trailing comma after the last field when the closing brace is on a new line. Forgetting it causes a compile error.
// Compile error: syntax error: unexpected newline, expecting comma or }
// p := Person{
// Name: "Maria",
// City: "Lisbon"
// }
Add the comma:
p := Person{
Name: "Maria",
City: "Lisbon",
}
Using unexported fields from another package. A struct literal in one package cannot directly set an unexported field defined in another package, even with the keyed syntax.
// In package a
// type user struct { name string; active bool }
// In package main
// import "a"
// u := a.user{name: "eve"} // compile error: unknown field 'name'
Only exported fields are addressable from outside the defining package in a literal. You’d need an exported constructor function instead.
Assuming positional literals will survive field additions. A field inserted anywhere in a struct definition — even at the end — changes the positional mapping, and the compiler will reject any literal that doesn’t supply a matching count. With a keyed literal, the same code continues to compile without changes.
Positional literals can break silently if types match:
In the worst case, a new field of a compatible type inserted in the middle may still compile but assign values to the wrong fields — for example, two int fields swapping meaning. This is rare but dangerous. Keyed literals prevent this class of bug entirely.
Overusing type elision in deeply nested literals. When you omit type names three or four layers deep, the code becomes harder to follow because the reader must backtrack to find the corresponding field type. Use explicit type names in the innermost literal when the structs are non-obvious.
Summary
Struct literals let you create a fully initialized struct value in a single expression. The keyed form (Field: value) is the safe default: it documents the mapping, allows you to omit fields, and stays valid as the struct evolves. Positional literals are useful for tiny, geometrically named types where the field order is part of the type’s identity and unlikely to change. When a struct contains another struct, Go allows you to elide the inner type name — a convenience that reduces repetition when the context is clear, but one that should be weighed against readability.
Once a struct literal is written, you usually need to read its fields or pass it around.