Basic Syntax
Program Structure
// optional, when we need external functionality // notably, rust has a prelude that is used by default. use std::io; // required, `main()` the entry of every rust program. fn main() { println!("Hello, world!"); }
Variables & Types
// variable
// most of the time, rustc infers the type.
let score = 90; // immutable variable
let first_name: char; // type annotation, optional
let mut height = 1.75; // mutable variable
// constant (computable at compile time)
const MAX: i32 = 100; // requires type annotation
const PI: f64 = 3.14; // requires initialization too
// array
let numbers = [1, 2, 3, 4, 5];
let mut str: [char; 5];
// tuple
let tup = (500, 6.4, 1);
let tuple: (i32, f64, char) = (42, 6.28, 'J');
// shadowing
let x = 5; // immutable (5)
let x = x + 1; // shadowing, new variable (6)
let x = x * 2; // shadowing, another new variable (12)
// basic types
i8, i16, i32, i64, i128
u8, u16, u32, u64, u128
isize, usize // architecture dependent
f32, f64
char // unicode scalar value
bool
// type conversion
let x: i32 = 42;
let y: f64 = x as f64;
let z: i32 = y as i32;
Operators
// arithmetic
+ - * / %
// `/` is integer division if both operands are integers.
// `%` is the remainder of the division.
// relational
== != > < >= <=
// logical
&& || !
// `&&` and `||` are short-circuit operators.
// bitwise
& | ^ ! << >>
// assignment
= += -= *= /= %= <<= >>= &= |= ^=
Control Flow
Branching
Branching in Rust is more powerful than just this, for details, see the Pattern Matching chapter.
// if-else expression (can "return" values)
if condition { /* ... */ }
else if condition { /* ... */ }
else { /* ... */ }
// match expression (can "return" values)
match value {
pattern1 => /* ... */,
pattern2 => /* ... */,
_ => /* ... */, // catch-all (wildcard)
}
Looping
// loop expression (while true)
loop { /* ... */ }
// while loop
while condition { /* ... */ }
// for loop
for element in iterable { /* ... */ }
// range
1..=5 // 1, 2, 3, 4, 5
1..5 // 1, 2, 3, 4
// break and continue
loop {
if condition { break; }
if condition { continue; }
}
// the `loop` can be labeled and `break` to the label.
'outer: loop {
'inner: loop {
break 'outer;
}
}
// it can also `break` with a value
let result = loop {
if condition { break 1; }
else { break 2; }
};
Functions
This is only a brief introduction to functions and closures. For details, see the Function chapter.
// function
// fn name(param: type) -> return_type { /* ... */ }
fn add(a: i32, b: i32) -> i32 {
a + b // last expression implicitly returned
}
let sum = add(3, 5);
// closure (anonymous function)
let closure = |a: i32, b: i32| -> i32 { a + b }; // functions are values.
let add = |a, b| a + b; // type is inferred.
let sum = add(3, 5);
Structs
struct Point {
// fields are private by default
x: i32,
// `pub` makes the field public
pub y: i32,
}
// methods
impl Point {
// associated function, also constructor
fn new(x: i32, y: i32) -> Point {
Point { x, y }
}
// captures `self` by immutable reference
fn get_x(&self) -> i32 {
self.x
}
// captures `self` by mutable reference
fn set_x(&mut self, x: i32) {
self.x = x;
}
}
// method implementation can be separated
impl Point {
// consumes `self`
fn move_to(self, x: i32, y: i32) -> Point {
Point { x, y }
}
}
// construction
let p0 = Point::new(0, 0);
let x = p.get_x();
let p1 = Point {
x, // field init shorthand
y: 4
};
let p2 = Point { y: 4, ..p1 }; // struct update syntax
// tuple struct
struct Color(i32, i32, i32);
let black = Color(0, 0, 0); // construction
let r = black.0; // accessing fields by index
let g = black.1;
let b = black.2;
// unit-like struct (no fields, marker)
struct PlayerMarker;
Enums
// marker enum
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
// with data
enum AppError {
NoContext,
IoError(io::Error),
InvalidInput {
encountered: String,
expected: String
},
}
let unknown = AppError::NoContext;
let io_err = AppError::IoError(/* ... */);
let invalid = AppError::InvalidInput {
encountered: "sapling".to_string(),
expected: "saplyn".to_string()
};
// methods (like structs)
impl AppError {
fn is_io_error(&self) -> bool {
match self {
AppError::IoError(_) => true,
_ => false,
}
}
}