module Structs {
// STRUCT BASICS
// a struct is a type with named, typed fields
// • structs are nominal types, meaning two structs are not the
// same type even if they have the same field names and types
// • structures are immutable by default (see section on mutability)
// • structures are stack-allocated/contained by default (see section on references)
// the following structure has two integer fields, x and y
struct Point {
x : int;
y : int;
}
fn test() {
// structs can be constructed using named arguments
let p1 = Point(x : 1, y : 2);
// structs can be constructed using positional arguments
let p2 = Point(1, 2); // x: 1, y: 2
}
// DEFAULT FIELD VALUES
// fields can have default values which are used
// if a value is not specifed when the struct is constructed
struct Shape {
origin: Point = Point(0, 0);
color: string = "#ff00ff";
rotation : double = 0;
}
fn test2() {
// construct a Shape with all default values
let s1 = Shape();
// construct a Shape with default field values except rotation
let s2 = Shape(rotation: 45);
}
// INCLUDING FIELDS FROM OTHER STRUCTS
// structs can include fields from other structs using ...,
// but all field names must still be unique. note that this is
// not inheritance - this is equivalent to copy/paste of the fields.
struct Line {
...Shape; // line now has all the fields of Shape
length : double;
}
fn test4() {
// construct a line, and specify value for origin field defined in Shape
let l1 = Line(origin: Point(1, 1), length: 3);
}
// INTERFACE IMPLEMENTATION
// structs can easily implement an interface with getters
// without having to implement the delegation manually
// define an interface with a get property called name
interface NamedObject {
name.get() : string;
}
// define a struct with a name field
struct Triangle {
name : string;
p1 : Point;
p2 : Point;
p3 : Point;
}
// indicate that Triangle struct implements NamedObject interface
// with this definition, the compiler will implement the interface
impl NamedObject {
...Triangle;
}
fn test5() {
// construct a triangle
let t1 = Triangle("mytriangle", Point(0, 0), Point(1, 2), Point(3, 4));
let n1 = t1.name; // access name field
// get NamedObject interface for triangle
let i1 = t1::NamedObject; // cast to interface type
let n2 = i1.name; // access name field via property getter on interface
}
// USING PROPERTY INTERFACES TO DEFINE FIELDS
// structs can also use interfaces as a way of defining the fields,
// making it easier to keep property accessor interfaces in sync
// with their implementations
// structures can also include interfaces whose members are only properties
// this will define a corresponding field for each property, with the same name
struct Circle {
...NamedObject; // adds a name : string; field
origin : Point;
radius : double;
}
// indicate that Circle struct implements NamedObject interface
impl NamedObject {
...Circle;
}
fn test6() {
// construct a circle
let c1 = Circle("mycircle", Point(0, 0), 1);
let n1 = c1.name; // access name field of circle
// get NamedObject interface for circle
let i1 = c1::NamedObject; // cast to interface type
let n2 = i1.name; // access name field via property getter on interface
}
// UNIT STRUCTURES
// a "unit" structure is a structure with no fields
// • unit structures are constructed by simply using the name of the structure
// without the usual ()
struct Empty {}
fn test7() {
let x : Empty = Empty;
if (x == Empty) {
// it's empty
}
}
// PRIVATE FIELDS
// To make a field of a structure private, add an leading underscore _ to the name.
// Private fields are only accessible from the namespace that defined the struct.
struct StructWithPrivateField {
x : int;
y : int;
_z : int; // field _z is only accessible from this namespace
}
}