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::Debug
is used by{:?}
, andfmt::Display
is used by{}
(see later); json style print{:#?}
use std::fmt;
importsfmt
write!(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::Debug
trait?
after a function which returnsResult
makes 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
,i128
andisize
(pointer size) as7
or7i32
(or10x
,10011b
, etc.) - unsigned integers:
u8
,u16
,u32
,u64
,u128
andusuze
(pointer size) as7u32
- floating point:
f32
,f64
as7.1
or7.1f64
- unicode characters:
char
as'a'
or'☺'
- boolean:
bool
astrue
orfalse
- static string:
str
as"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.0
andpair.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 = LongOperationsStructName
ortype IoResult<T> = Result<T, IoError>
. - In struct methods, one can refer to the object with default alias
Self
use
keyword 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_iter
which consumes (moves) the collectioniter
which borrows each elementiter_mut
which 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;
}