Rust cheetsheet
This page serves as a quick reference constructions in Rust programming language. Knowledge of the language is assumed so the code explained minimally. However, for a skilled programmer this page may serve as a syntax reference.
Main and prints
fn main() {
// todo here
}
fn function(par1: Type, par2: Type) -> ReturnType {
expressions;
let val = function2(par1, par2, par3);
returned_value // or return returned_value;
}
format!,print!(println!), andeprint!for string formatting and printingformat!("{} {:b} {:.5} {1:>20} {1:0>width}","first","one",width=3);prints in binary, decimals, alligned, and 0-alligned- traits
fmt::Debugis used by{:?}, andfmt::Displayis used by{}(see later); json style print{:#?} use std::fmt;importsfmtwrite!(buf, "val: {}", val)writes formatted data into a buffer.struct Structure(i32, String);- return keyword exists, but we can just leave out
;after the last command to return its result
Implement display for a structure to be able to format/print it with {}.
impl fmt::Display for Structure {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug)]autoimplementsfmt::Debugtrait?after a function which returnsResultmakes it so that if error occurs the error is returned immediatelyvec![1, 2, 3]macro to create vector instance with given entries
Types and operators
- signed integers:
i8,i16,i32,i64,i128andisize(pointer size) as7or7i32(or10x,10011b, etc.) - unsigned integers:
u8,u16,u32,u64,u128andusuze(pointer size) as7u32 - floating point:
f32,f64as7.1or7.1f64 - unicode characters:
charas'a'or'☺' - boolean:
boolastrueorfalse - static string:
stras"abc" - arrays:
i32[]as[1,2,3] - tuples:
(i32,f64,bool,(str,i32))as(1,2,true,("inner tuple",3)) - unit type:
()as()
Types can be explicit with : or inferred, but not dynamic.
We can cast one type to another with as keyword as var as i32.
let logical: bool = true;
let a_float: f64 = 1.0; // Regular annotation
let an_integer = 5i32; // Suffix annotation
let default_float = 3.0; // default `f64`
let default_integer = 7; // default `i32`
let mut inferred_type = 3; // Type i64 is inferred from the next line
inferred_type = 4294967296i64;
let inferred_type = true; // shadowing
- typical operators
+-&&||!&|^<<>> - numbers can be interleaved with
_for readibility as1_000_000u32 - creating tuples
let t = (1,2,3,var); - destructuring tuples
let (a,b,c,d) = t; - type of an array is
[type; length]as[i32; 5]for[1,2,3,4,5]or for a fixed value[1; 5] - slice is a pointer to a subarray created as
&arr[1 .. 4]
Custom types struct and enum (const and static).
There are three types of structures.
- classic structs
- Instantiate with
Struct {3, 5}orStruct {x: 3, y: 5}but also with justStruct {x, y}when the fields and variable names coincide. - One can construct an object based on another (struct update) as
let struct = Struct {x: 3, ..other_struct};. - Destructure by
let Struct { x: left, y: right } = point;
- Instantiate with
- tuple structs / named tuples
- Instantiate with
let pair = Pair(1, 2); - Access with
pair.0andpair.1 - Deconstruct with
let Pair(a, b) = pair;
- Instantiate with
- unit structs, which are empty but named
Desconstruction can be nested, e.g. let Rectangle{top_left:Point{x:a,y:b},bottom_right:Point{x:c,y:d}} = r;
enum contains exactly one of its defined values.
enum Event {
PageLoad,
KeyPress(char),
Click { x: i64, y: i64 },
}
These are by default numbered from 0.
If we set Val = 3, in the enum, then that value is used instead.
fn inspect(event: Event) {
match event {
Event::PageLoad => println!("page loaded"),
Event::KeyPress(c) => println!("pressed '{}'.", c),
Event::Click { x, y } => { println!("clicked at x={}, y={}.", x, y); },
}
}
- Type aliases
type Op = LongOperationsStructNameortype IoResult<T> = Result<T, IoError>. - In struct methods, one can refer to the object with default alias
Self usekeyword defaults values to a given namespace as follows
use crate::Status::{Poor, Rich}; // list where we do not have to use Status::Rich but just Rich
use crate::Work::*; // include all
When using match, one can use Some(ref n) to avoid moving n.
This is quite different from Some(&ref) as ref is not matched against (otherwise a reference is expected).
There are two types of constants: const and static.
Values which may be null are enclosed in Option<T> and may contain either Null or Some<T> which can be recognized with match.
Retype value with as keyword as x as i32; note that it does not overflow but saturates.
To for an overflow we have to use unsafe together with e.g. 300.to_int_unchecked::<u8>() function.
We can measure size of values by std::mem::size_of_val(&val).
Covert with From, Into, and failable TryFrom and TryInto.
Convert with string using fmt::Display and FromStr.
use std::convert::From;
#[derive(Debug)]
struct Number { value: i32, }
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
...
let val = 30;
let num = Number::from(val);
let num: Number = val.into();
Basic flow of control examples:
if cond { // basic if/else
} else if cond {
} else {
}
loop { // basically while true
// use continue & break
}
// continue & break outer loops with labels
// and return values from cycles
let res = 'go: loop {
loop {
break 'go 2;
}
}; // assignment needs to be ended with ;
while cond { // usual while loop
cond = false;
};
for n in 1..101 { ... }
for n in 1..=100 { ... } // inclusive range
Iterator can be created with
into_iterwhich consumes (moves) the collectioniterwhich borrows each elementiter_mutwhich mutably borrows each element
match num {
1 => ... , // matches 1
2 | 3 => ... , // this matches 2 or 3
4..9 => ... , // matching range
n @ 5..=13 => ... , // binding (useful for matching functions)
_ => ... , // anything else
}
match triple {
(0, y, z) => ... ,
(1, ..) => ... ,
_ => ... ,
}
match structure {
St { x: (1, b), y } => ... ,
St { x: 2, y: i } => ... ,
St { x, y } if x==y => ... , // so-called guard
St { x, .. } => ... ,
}
match enumvar {
Enm::Var1 => ... ,
Enm::Var2(x, y) => ... ,
// no need for default if all cases are covered
}
Reference can be dereferenced with *.
Destructuring uses &, ref, and ref mut.
let varref = &4;
let ref varref = 3;
match varref {
&val => ... ,
}
match *varref {
val => ... ,
}
let var = 3;
match var {
ref val => ... ,
}
match var {
ref mut val => ... ,
}
if let Some(i) = number { ... }
if let Foo::Bar = a { ... }
while let Some(i) = number { ... }
Functions
fn func1(var: i32, var2: i32) -> bool {
if rhs == 0 { return false; } // return from middle
lhs % rhs == 0 // last expression returned when ; is omitted
}
fn func2(var: i32) { ... } // same as -> ()
Methods, closures
fn consume(self) -> Self { ... } // Consuming `self`
fn borrow(&self) -> &i32 { ... } // Borrowing `self`.
fn borrow_mut(&mut self) -> &mut i32 { ... } // Borrowing `self` mutably.
// closure captures variable x by first possible of: &, &mut, value
// respective traits for these are Fn, FnMut, FnOnce
let closure = |i: i32| -> i32 { i + x }; // i32 can be inferred both parameter & return
// the value of x is now borrowed as reference upto the last use of the closure
let res = closure();
let forcedmove = move |j| -> { j + y }; // take ownership of y
// use closures as parameters using generics
fn apply<F>(f: F) where F: Fn() { f(); }
fn call_me<F: Fn()>(f: F) { f(); }
// function may also be supplied in place of closure
fn function() { ... }
call_me(function);
// return closures as 'some' type which implements a given trait
fn create_fn() -> impl Fn() { ... }
Higher order fuctions are used like this:
let sum_of_squared_odd_numbers: u32 =
(0..).map(|n| n * n) // All natural numbers squared
.take_while(|&n_squared| n_squared < upper) // Below upper limit
.filter(|&n_squared| is_odd(n_squared)) // That are odd
.fold(0, |acc, n_squared| acc + n_squared); // Sum them
A function may not return control to its called when it purpusefuly panic!s.
This is represented by type marked as !.
let x: ! = panic!("oh no!");
A function which can end in error should return Result<okType,errType>.
Return type has a built-in feature: typing ? after function which returns Result returns error immediately if error occurs, or gives the value if Ok was the result.
fn fun(val: i32) -> Result<i32,String> {
if ... {
Ok(val)
}else{
Err("bad value")
}
}
fn main() -> Result<_,String>{
let res: Result<i32,String> = fun(2);
match res { // result contains enum
Ok(int) => ... ,
Err(err) => ... ,
}
let val: i32 = fun(3)?; // Err case propagates up
}
Todo: Option
Generics
fn fun<T>(list: &[T]) -> T where T: Trait {
...
}
struct Point<T> {
atr: T,
}
impl<T> Point<T> {
fn generic_method(&self, val: T) -> &T { ... }
}
// implemented just for T which has the Trait
impl<T: Trait> Point<T> {
fn conditional_impl(&self) { ... }
}
Traits
pub trait Summary {
fn summarize(&self) -> String;
}