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