Use the struct type when creating values that contain multiple other values within. A struct's member values are called properties. Each property has a unique name, a specified type, and possibly a default value.
Note: structs are not the only type to support properties. Traits, Interfaces, Allocs, Perms and other types also support properties for similar, but more specialized needs.
First, you must declare a specific struct layout by name. For example:
struct Point x f32 y f32
This defines a struct type named Point that contains two properties named x and y. Both properties are floating point numbers.
Property declarations look like variable declarations:
- A permission may be specified before the property name. If unspecified, mut is assumed.
- The property's name and type must be specified. Property names that begin with an underscore are considered private. Private properties cannot be accessed outside of the struct's methods.
- A default value may be specified after the type and an equal sign. The default value must be a literal and may be used to help initialize a newly created struct.
Once declared, the struct type may be used the same way as any other type. For example, this declares a Point variable:
imm pt Point;
A new struct value is created and initialized using a literal or an initializer.
A struct literal begins with the struct name followed by the initial values for all properties in square brackets.
imm pt = Point [x: 3., y: 4.] // Using property names imm pt2 = Point [3., 4.] // When property names are omitted, order matters.
Several rules apply to literals:
- A value must be specified for all properties that were not declared with a default value.
- Private properties without a default value prevent the use of literals external to the type's methods.
Copy vs. Move
By default, most declared structs are 'copy' types. However, if a struct defines any field whose type is 'move' (e.g., a 'lex' or 'uni' reference), the entire struct is treated as a 'move' type. For further information about 'copy' vs. 'move', please consult the move semantics page.
struct copying has potential downsides: a) the larger the struct, the slower the copy, b) changing a copy does not change the original. These limitations can be addressed 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]
Any public property within a struct may be accessed using the . operator, specifying the object on the left and the property name on the right:
imm dist = (pt.x*pt.x + pt.y*pt.y).sqrt
Within a struct's methods, only the property name needs to be specified, just as if it were a variable.
fn dist() f32 (x*x + y*y).sqrt // x is equivalent to self.x
A property can be changed by putting the property name to the left of an assignment operator:
fn setOrigin(self &mut) x,y = 0f,0f
Note: From the outside, a property and a computed property (a get/set method) look identical. The user of a struct does not care if it is working with a stored value or a value mediated by methods.
Mutation of a property is allowed only if the permissions on both the object and the property permit it.
It is possible to use the & operator to obtain a borrowed reference to a specific property within a structure:
imm pt = Point[x: 3f, y: 4f] imm refx = &pt.x *refx // 3f