Types
Structs
Unit Structs
No fields:
struct Unit
pvt struct PvtUnit
Newtype / Tuple Structs
Positional fields in parentheses:
struct Newtype(i64)
struct Pair(i64, i64)
Fields can have visibility:
struct TupleVis(pvt i64, String)
Record Structs
Named fields in braces:
struct Point {
x: i64,
y: i64,
}
Field visibility:
struct RecordVis {
pvt name: String,
age: i64,
}
Generics
Type parameters with optional bounds:
struct Container<T> {
value: T,
}
struct Bounded<T: Clone + Debug> {
value: T,
}
struct Multi<T: Clone, U: Display> {
first: T,
second: U,
}
Where Clauses
Complex bounds can use where:
struct WithWhere<T, U> where T: Clone + Debug, U: Display {
first: T,
second: U,
}
struct BoundedTuple<T>(T) where T: Clone
Attributes
#[derive(Debug, Clone)]
struct Annotated {
field: i64,
}
#[derive(Debug)]
#[repr(C)]
struct CRepr {
x: i32,
y: i32,
}
Multiple attributes can be stacked.
Everything Combined
#[derive(Debug, Clone, PartialEq)]
pvt struct FullBellsAndWhistles<T, U: Default> where T: Clone + Debug {
pvt id: i64,
name: String,
data: T,
extra: U,
}
Recursive Structs
Use Box for indirection:
struct List<T> {
head: T,
tail: Option<Box<List<T>>>,
}
Struct Literals
Creating struct values:
Point { x: 1, y: 2 }
Shorthand when variable names match fields:
let x = 1
let y = 2
Point { x, y } // same as Point { x: x, y: y }
Spread to copy remaining fields:
let p = Point { x: 1, y: 2 }
Point { x: 10, ..p } // y comes from p
Path-qualified:
std::geo::Point { x: 1, y: 2 }
Nested:
Line { start: Point { x: 0, y: 0 }, end: Point { x: 1, y: 1 } }
Enums
Unit Variants
C-style enumerations:
enum Color { Red, Green, Blue }
pvt enum Internal { A, B }
Tuple Variants
Variants carrying unnamed data:
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
Record Variants
Variants with named fields:
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
Mixed Variants
An enum can mix unit, tuple, and record variants:
enum Message {
Quit,
Move { x: i64, y: i64 },
Write(String),
ChangeColor(i64, i64, i64),
}
Generics, Bounds, and Where Clauses
enum Wrapper<T: Clone> {
Item(T),
Empty,
}
enum Constrained<T, U> where T: Clone, U: Debug {
Both(T, U),
First(T),
}
Recursive Enums
enum Tree<T> {
Leaf(T),
Node(Box<Tree<T>>, Box<Tree<T>>),
}
GADTs
Variants can specialize their return type with ->:
enum Expr<T> {
LitInt(i64) -> Expr<i64>,
LitBool(bool) -> Expr<bool>,
Add(Expr<i64>, Expr<i64>) -> Expr<i64>,
If(Expr<bool>, Expr<T>, Expr<T>) -> Expr<T>,
Eq(Expr<i64>, Expr<i64>) -> Expr<bool>,
}
This enables type-safe expression trees where the type parameter tracks the result type of each node.
Type Aliases
type Byte = i8
type Result<T> = std::result::Result<T, MyError>
type Pair<A, B> = Tuple2<A, B>
type CloneVec<T: Clone> = Vec<T>
type Mapped<T, U> = Map<T, U> where T: Clone, U: From<T>
pvt type Internal = InternalImpl
Tuples
Ordered, fixed-size groups of values:
(1, 2)
(42, "hello", true)
(1, (2, 3)) // nested
Arrays
Fixed-size, homogeneous collections:
[1, 2, 3]
[] // empty
["hello", "world"]
[[1, 2], [3, 4]] // nested
Array types are written [T; n]:
fn make_array() -> [i64; 3]:
[1, 2, 3]