Structs
A struct declares a named type made of named fields. A value of the type holds every field at once. Two structs are different types even when their fields are identical, so a function that asks for a Point cannot be handed something else that happens to have an x and a y.
A struct declares only its data. Methods, constructors, operators and destructors are added in a separate extend block.
struct = [ attributes ] [ "pub" ] "struct" name [ type-parameters ] "{" { field } "}"
field = [ "pub" ] name ":" type ";"
struct Point {
x: int;
y: int;
}
struct Box {
corner: Point;
width: int;
height: int;
}
struct Empty {}
Each field is name: Type and ends with a semicolon. A field may have any type that has a known size: a primitive, an array, a slice, a pointer, an optional, a tuple, another struct. By convention the type name is PascalCase and field names are camelCase.
Struct literals
A value is built with a struct literal: the type's name and a value for every field, in braces. The fields may come in any order, because each is named:
let origin = Point { x: 0, y: 0 };
let corner = Point { y: 2, x: 5 };
let box = Box { corner: corner, width: 4, height: 3 };
Every field must be given. A field has no default value — x: int = 0; in a declaration is a syntax error — so a literal that leaves one out is refused:
error: initializer for 'Point' is missing required field 'y'
error: struct 'Point' has no field 'z'
note: available fields are 'x' and 'y'
When building a value takes more than listing its fields, give the type a constructor: Point(1, 2) is a constructor call, not a literal. A literal always remains available where every field is visible.
Fields
A field is read with ., and fields of nested structs by chaining: box.corner.x. A field is assigned like a variable, and the same rule applies: the value must be a var. Under let the whole struct is read-only, every field included.
var cursor = Point { x: 1, y: 1 };
cursor.x = 10;
cursor.y += 5;
let fixed = Point { x: 1, y: 2 };
fixed.x = 5; // error: cannot modify immutable variable 'fixed'
A field can also be read through a reference or a pointer to the struct with the same .; writing needs a &var T or a *var T.
Visibility
A field is private to its package unless it is marked pub, separately from the struct itself:
pub struct Point {
pub x: int;
y: int;
}
Another package that imports Point can read and write x but not y. Because a literal must name every field, it cannot build a Point at all; it calls a public constructor instead:
error: struct field 'y' is private to package 'Shapes'
error: struct 'Point' cannot be initialized outside its package because it has private fields
help: use a public constructor instead
Within its own package every field is visible. See Visibility.
Values, not references
A struct is a value. Assigning it, passing it to a by-value parameter and returning it copies every field, and the copy is independent of the original:
var a = Point { x: 1, y: 2 };
var b = a; // a copy
b.x = 9; // a.x is still 1
A function that should read a large struct without copying it takes &Point; one that should change the caller's struct takes &var Point. A struct whose type declares that it cannot be copied is moved instead, with <-; see Copy and move.
Self-reference
A struct cannot contain itself by value, since its size would be infinite. A linked structure holds a pointer to the next node instead, usually an optional one:
struct Node {
value: int;
next: (*Node)?;
}
A field such as next: Node;, or next: Node?;, which holds the value in place too, is an error. So is a cycle through other types, and the same rule covers variants and unions:
error: struct 'Node' contains itself by value through 'next'
note: a value that holds itself in place would have no finite size
help: hold it behind a pointer, as '*Node' or '(*Node)?'
Equality
Two values of the same struct type compare with == and != field by field, in declaration order. Every field must support == itself; a field such as a char8[..] slice, which has no ==, makes the comparison unavailable:
let same = origin == Point { x: 0, y: 0 }; // true
error: structural equality for 'Named' is unavailable because element type 'char8[..]' has no '==' operator
A struct that declares its own == in an extend block uses that instead; see Operators. Structs have no built-in ordering: < needs a declared operator.
Generic structs
A struct may take type parameters, written after its name. Each use names the type arguments, in the type and in a literal:
struct Pair<T> {
first: T;
second: T;
}
let pair = Pair<int> { first: 1, second: 2 };
See Generic types.
See also
- Methods — functions that belong to a struct
- Constructors — building values through a function
- Destructuring and patterns — taking a struct apart
- Memory layout — field order, alignment and padding
- Learn: Struct, Structural equality