kuniga.me > Docs > Rust Cheatsheet
Rust Cheatsheet
Index
Basic types
Type names
Arrays
Initialize
Iterate
Bool
Enum
Integers
Bit operations
Iterator
Optional
Pair
String
Types
String (variable length)
Operations
Struct
Destructuring
Methods
Tuple
Functions
Closure
Multi-line
Flow Control
Conditional
Loops
Data structures
BTreeMap
BTreeSet
Vector
Initialize
Inserting
Iterating
Mapping
Filtering
Length
Sorting
Destructured assignment
HashMap
HashSet
Queue
Object Oriented
I/O
Read from stdin
Read CLI arguments
Printing to stdout
Math
Exponentiation
Square root
Mutability
Attributes
Modules
Nested
Ownership
Basic types
Type names
char
f32
, f64
- float point type
Arrays
Arrays are of fixed size. For variable size, see Vec
.
Initialize
// Initialize array
let arr : [ i32 ; 3 ] = [ 1 , 2 , 3 ];
let arr : [ i32 ; 10 ] = [ 0 ; 10 ];
Iterate
let it :
let v : Option < Self :: Item > = it .next ()
Bool
Type: bool
Examples: true
, false
Enum
enum Direction {
N ,
E ,
S ,
W ,
}
Integers
Types: i8
, i16
, i32
, i64
, u8
, u16
, u32
, u64
Bit operations
!
is the Rust version of ~
Iterator
Note that Iterator
is not a class but rather a trait that classes implement.
Get the next element:
// returns Split class which implements Iterator
let mut parts = s .split ( ',' );
let e : Optional <& str > = parts .next ();
NOTE: next()
is not idempotent.
Optional
// Handle option:
match my_option {
Some ( value ) => value ,
None => 1 , // handle null value
}
Create Some
:
Some ( 1 )
Throw if None
:
my_option .unwrap ()
Test if some:
my_option .is_some ()
Test if none:
my_option .is_none ()
Pair
Done via tuples. See Tuple .
String
Types
String
- string object
&str
- string slice
&'static str
- string literal
String (variable length)
// Empty string
let mut my_str : String = "" .to_owned ();
// Other form
let mut my_str = String :: from ( "Hello" );
// Length
my_str .len ();
// Iterate over its characters
for c in my_str .chars () {
// do something with c
}
Operations
let concatenated = format! ( "{}{}" , a , b );
From literal strings:
let s : String = "hello" .to_owned ();
Convert to int:
let i = s .parse :: < i32 > () .expect ( "Should be numeric" );
Convert from int:
let i : i32 = 10 ;
let s = i .to_string ();
Convert to Vec<char>
:
let cs : Vec < char > = s .chars () .collect ();
Split:
let parts : Vec <& str > = s .split ( ',' ) .collect ();
Split into multiple lines. There’s a shortcut for splitting by the character \n
:
let parts : Vec <& str > = s .lines () .collect ();
Substring:
s .contains ( p );
Trim:
let trimmed = s .trim ();
Struct
keywords: record / object / shape
struct Tree {
guess : Vec < i32 > ,
children : Vec < Tree > ,
}
Destructuring
let foo = Foo { x : ( 1 , 2 ), y : 3 };
let Foo { x : ( a , b ), y } = foo ;
Methods
struct Rectangle {
length : u32 ,
width : u32 ,
}
impl Rectangle {
fn area ( & self ) -> u32 {
self .length * self .width
}
}
Tuple
Type: (T1, T2)
, e.g. (i32, bool)
Create:
let tup : ( i32 , String ) = ( 64 , "hello" )
Access:
tup .0 // 64
tup .1 // "hello"
or via destructuring:
let ( n , s ) = & tup ;
Functions
fn myFun ( arg1 : i32 , arg2 : i32 ) -> i32 {
}
Rust doesn’t support default arguments
Closure
keywords: lambda
let plus_one = | x : i32 | x + 1 ;
Multi-line
let multi_line = | x : i32 | {
let mut result : i32 = x ;
result += 1 ;
result
}
Flow Control
Conditional
if n < 0 {
print! ( "{} is negative" , n );
} else if n > 0 {
print! ( "{} is positive" , n );
} else {
print! ( "{} is zero" , n );
}
Loops
for i in 0 .. 3 {
println! ( "{}" , i );
}
See also “Iterating” on different data structures.
Data structures
BTreeMap
BTreeMap
is another implementation of a efficient key-value (the other being HashMap
). One analogy for C++ is that BTreeMap
is std::ordered_map
and HashMap
is std::unordered_map
.
use std :: collections :: BTreeMap ;
// Create empty
let mut my_map = btreemap! {};
// Create initialized
let my_map = btreemap! {
"blue" => 1 ,
"green" => 2 ,
"red" => 3
};
BTreeSet
There’s an analogy between BTreeSet
and HashSet
with BTreeMap
and HashMap
.
// Create empty
let mut my_map = btreeset! [];
// Create initialized
let fruits = btreeset! [
"apple" ,
"banana"
]
Vector
Initialize
let mut vec = Vec :: new ();
Fixed size, same value:
let mut vec = vec! [ 0 ; 100 ];
Inserting
vec .push ( 1 );
Iterating
for item in vec .iter () {
...
}
Mapping
let u = vec! [ 1 , 2 , 3 ];
let v : Vec < _ > = u .iter () .map ( f ) .collect ();
Filtering
let u = vec! [ 1 , 2 , 3 ];
let v : Vec < _ > = u .iter () .filter ( f ) .collect ();
In-place
let mut u = vec! [ 1 , 2 , 3 ];
u .retain ( f );
Length
vec .len ()
Sorting
vec .sort_by (| a , b | a .cmp ( b ))
Destructured assignment
Like in Python, we can do destructured assignment by assuming a fixed length of a vector, but we have to handle the other cases:
let [ a , b ] = vec .as_slice () else {
panic! ();
}
HashMap
Reference: HashMap
use std :: collections :: HashMap ;
// Type definition
HashMap < String , String > ;
// Create empty
let mut my_map = HashMap :: new ()
// Create initialized
let my_map = HashMap :: from ([
( "blue" , 1 ),
( "green" , 2 ),
( "red" , 3 ),
]);
// Insert
my_map .insert (
"key_a" .to_string (),
"value_a" .to_string (),
);
// Access
match my_map .get ( "key_a" ) {
Some ( value ) => println! ( "value={}" , value ),
None => println! ( "not found" )
}
// Update
if let Some ( value ) = my_map .get_mut ( key ) {
* curr_value = 1 ;
}
// All values
for value in my_map .values () {
}
// All keys
for key in my_map .keys () {
}
HashSet
Use:
use std :: collections :: HashSet ;
Create:
let s = HashSet :: new ();
From vector:
let v = vec! [ 1 , 2 , 3 ];
// cloned needed if borrowing v
let s : HashSet < _ > = v .iter () .cloned () .collect ();
Set intersection:
let i : HashSet < _ > = s1 .intersection ( & s2 ) .cloned () .collect ();
Queue
use std :: collections :: VecDeque ;
// Create
let mut queue = VecDeque :: new ();
// Enqueue
queue .push_back ( "a" );
// Dequeue
if let Some ( x ) = queue .pop_front () {
// use x
}
// Is empty?
if ! queue .is_empty () {
// use queue
}
Object Oriented
pub structure MyClass {
my_field : bool ,
}
impl MyClass {
// Constructor-like
pub fn new () -> MyClass {
return MyClass {
my_field : true ,
}
}
// Read Method
pub fn set ( & self , value : bool ) {
self .my_field = value ;
}
// Write Method
pub fn set ( & mut self , value : bool ) {
self .my_field = value ;
}
}
I/O
Read from stdin
use std :: io ::{ self , Read };
let mut input = String :: new ();
io :: stdin () .read_to_string ( & mut input )
.expect ( "Failed to read input" );
Read CLI arguments
use std :: env ;
// Skip program name
let args : Vec < String > = env :: args () .skip ( 1 ) .collect ();
Printing to stdout
Vector:
let vec = vec! [ 1 , 2 , 3 , 4 , 5 ];
println! ( "Vector: \n {:#?}" , vec );
Math
A lot of the math operations are methods on the numerical types.
Exponentiation
let b : i32 = 10 ;
let p10 : i32 = b .pow ( 2 as u32 );
Note that the exponent has to be positive, since a negative one could change the type of the base to floating point.
Square root
let x : f64 = 10.0 ;
let y : f64 = x .sqrt ();
Not defined for integer types.
Mutability
Variable doesn’t need to be mutable if it’s initialized only once:
let x : i32 ;
if check () {
x = 1 ;
} else {
x = 2 ;
}
Attributes
Attributes are in the form #[foo]
and placed on top of functions, structs and modules to add metadata to it, e.g.
#[test]
fn test_invalid_argument () {
...
}
or
#[derive(Clone, Debug, Eq)]
struct Tree {
...
}
Modules
Modules add namespace to functions
Functions defined inside a module are private unless qualified with pub
Declaration:
mod math {
fn add ( a : i32 , b : i32 ) -> i32 {
a + b
}
pub fn sub ( a : i32 , b : i32 ) -> i32 {
a - b
}
}
Usage:
fn f () {
math :: sub ( 1 , 2 );
}
Nested
Modules can be nested but because of visibility being private by default, inner modules must be made explicitly public:
mod outer {
pub mod inner {
pub fn f () {
println! ( "Hello world" );
}
}
}
fn f () {
outer :: inner ( 1 , 2 );
}
Ownership
In Rust we have 3 ways of passing data from one variable to another:
Copy (default C++ mode)
Borrow (default Python mode, C++ references)
Move (C++ std::move)
There’s a convention for classes to implement these different modes.
Mode / semantics
API
Copy
to_
Borrow
as_
Move
into_
Reference: Rust API Guidelines