lang::struct¶
Product type declaration.
Functional record update¶
A struct literal may spread a base value with ..base and override
individual fields:
- Explicit fields win over the base for the same name.
- Exactly one
..basespread is allowed (a second is a parse error). - A spread references every field the literal does not name, so the whole struct has to be visible where the update is written. A struct with any private field cannot be updated from outside the module that declares it, exactly as it cannot be constructed there - see visibility.
- Fields copied from the base share its heap children and are retained, so the base stays usable after the update with no double-free. Output is identical across the VM, Cranelift, and LLVM tiers.
Declaration and construction¶
Struct declarations follow Rust's three shapes: unit structs, named-field structs, and tuple structs. Empty named structs use braces, and empty tuple structs use parentheses:
struct Unit
struct Empty {}
struct EmptyTuple()
struct Pt { x: i64, y: i64 }
struct Pair(String, i64)
let unit = Unit
let empty = Empty {}
let empty_tuple = EmptyTuple()
let p = Pt { x: 3, y: 4 } // keyed fields, any order
let pair = Pair("row", 4)
println!("{} {}", p.x, p.y)
println!("{} {}", pair.0, pair.1)
let Pt { x, y } = p
Named structs must be constructed with keyed fields in Name { field: value };
both Name(...) and positional Name { value } forms are rejected. Unit
structs use either Name or Name {}, while tuple structs must be constructed
with Name(...).
On one line, commas separate fields. In a multiline declaration or literal,
newlines separate fields. Multiline commas are accepted for migration and
gos fmt removes them:
Value semantics: copy and compare with no derive¶
Structs are value types. Binding or .clone()-ing copies the whole value
(heap children retained), and == / != / < / <= / > / >= are
synthesized automatically - no #[derive] needed - whenever every field
is comparable (scalars, String, nested comparable types). Ordering is
lexicographic by field declaration order:
struct Point { x: i64, y: i64 }
let a = Point { x: 1, y: 2 }
let b = a.clone() // `clone` is a universal builtin
println!("{}", a == b) // true, no derive
println!("{}", a < Point { x: 1, y: 3 }) // true (lexicographic by field)
A user impl of eq / cmp overrides the synthesized comparison.
Derivable traits¶
#[derive(...)] is limited to Debug, Default, PartialEq, Eq,
PartialOrd, and Ord, synthesized as real source so {:?},
Type::default(), and the comparisons work on every tier. The derive
only forces synthesis where the automatic gate is conservative (generic
or container-typed fields):
Clone, Copy, Hash, Display, Serialize, and Deserialize are
not derivable (GT0025): copying, hashing, and serialization are
already automatic. Conversion / operator traits (From, Add, ...) are
written impl Trait for T, not derived.