structs

A struct is a type used to package together several values of specific types. A struct may optionally also establish the methods used to handle its values.

struct Declaration

The declaration of a struct type names it and lists the named fields (values) in the structure and their types. By convention, type names begin with a capital letter:

struct Point
    x f32
    y f32

Each field may specify a permission. If unspecified, mut is assumed.

Field names that begin with an underscore are considered private. They cannot be accessed outside of the struct's methods.

struct Variables and Literals

Variable declarations may specify a declared struct type:

// two new points
imm pt1 Point;
imm pt2 Point;

So long as the struct has no private fields, a new variable declaration may be typed and initialized with a struct literal. The struct literal uses the struct's name and then the initial values for all fields in curly braces:

imm pt = Point {x: 3., y: 4.}
imm pt2 = Point {3., 4.} // Field names are optional

Copy vs. Move

As long as a struct has no fields that are references, assignment and function calls are handled by making a full copy of the struct, just like with integers and floats:

imm pt = Point {x: 3f, y:4f}
imm pt2 = pt     // pt2 is a full copy
func(pt2)        // this function call creates a third copy

Since they are independent copies, changing one will not change the other.

Should the struct contain any references (and not implement .clone()), an assignment or function call actually moves the value:

struct Node
    nbr: &mut i32
imm life = 42
imm node1 = Node {nbr: &life}
imm node2 = node1
imm node3 = node1   // ERROR! node1 is no longer usable

struct References

struct copying has two potential limitations: a) the larger the struct, the slower the copy, b) changing a copy does not change the original. It is possible to address these limitations by borrowing a reference to a struct and then passing around and using the reference in place of the struct.

fn main()
  imm pt = Point {x: 3f, y: 4f}
  imm dist = dist(&mut pt)  // dist may modify the contents of pt

Similarly, an allocator may be used to allocate a new struct. The allocator returns a reference to the struct:

imm pt = &gc mut Point{x: 3f, y: 4f}

Field access

Any field within a struct may be accessed using the . operator, specifying the structure on the left and the field name on the right:

fn dist(pt Point)
    (pt.x*pt.x + pt.y*pt.y).sqrt()

The same technique may be used to change a structure's field:

fn init(pt &mut Point)
    pt.x = pt.y = 0f

Mutation of s field is allowed only if the permissions on both the variable and the field permit it.

It is possible to use the & operator to obtain a borrowed reference to a specific field within a structure:

imm pt = Point{x: 3f, y: 4f}
imm refx = &pt.x
*refx                     // 3f

Methods

Although a struct type need not declare any methods, it may. This includes one or more constructors (at least one is needed if the struct has any private fields). A drop method should also be defined if clean-up logic must be run before an instance is destroyed.

These methods may be invoked on any instance of the struct.

tuples

A tuple is simply an ad hoc (undeclared) struct. When you return multiple values from a function, that is a tuple. When you use parallel assignment, that too is a tuple.

_