Rust uses snake case convention:
Printing data structures is possible using annotations
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } let rect1 = Rectangle { width: 30, height: 30, }; println!("{:?}", rect1); // inline println!("{:#?}", rect1); // multiline
#[allow(unused_variables, unused_mut)] #[allow(unused)] #[allow(dead_code)] #[macro_use] // allows to use macros from extern crate
Attribute at a crate level
#![allow(unused)]
cargo new PROJECT_NAME (--bin/lib) cargo build --release cargo run cargo update cargo doc --open
CLI comands
cargo install diesel_cli diesel setup diesel migration generate create_users diesel migration run diesel migration redo diesel print-schema > src/schema.rs
#[derive(Queryable)] pub struct UserModel { ... }
(signed i8, unsigned u8) (isize defaults to your computer architecture 32/64 bit)
i8, i16, i32, i64, i128, isizei32 even on 64 bit machinesf32(single precision), f64(double precision)f64char specified with single quotes let c = 'z' fn main() { let tup: (i32, f64, u8) = (500, 6.4, 1); let (x, y, z) = tup; let five_hundred = tup.0; }
let a: [i32; 5] = [1, 2, 3, 4, 5]; let a = [3; 5]; // let a = [3, 3, 3, 3, 3];
let a = [1, 2, 3, 4, 5]; let index = 10; llet element = a[index]; //runtime error. Rust does not allow to access memory
Function bodies are made of statements and optionally end with an expression.
let x = 3;4+6let x = 4+6;;, adding semicolon will turn it into statement which will not return valuefn five() -> i32 { 5 } fn main() { let x = five(); println!("The value of x is: {}", x); }
let rect1 = (30, 50); fn area(dimensions: (u32, u32)) -> u32 { dimensions.0 * dimensions.1 }
Rust does not transform to bools automatically
let x = 5; if x {} // error if x != 0 {} // correct
Condition in let statement
let condition = true; let number = if condition { 5 } else { 6 };
Rust has 3 types of loops: loop, while, for
Executes until you explicitly tell it to stop
loop { println!("again!"); }
fn main() { let mut counter = 0; let result = loop { counter += 1; if counter == 10 { break counter * 2; } }; println!("The result is {}", result); }
fn main() { let mut number = 3; while number != 0 { println!("{}!", number); number -= 1; } println!("LIFTOFF!!!"); }
fn main() { let a = [10, 20, 30, 40, 50]; for element in a.iter() { println!("the value is: {}", element); } }
Struct instances are mutable.
struct User { username: String, email: String, sign_in_count: u64, active: bool, } let user1 = User { username: String::from("A"), email: String::from("a@a.a"), active: true, sign_in_count: 1, }; let user2 = { username: String::from("B"), ..user1 }
struct Color(i32, i32, i32); struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0);
impl Rectangle { fn area(&self) -> u32 { self.height * self.height } } let area = rect1.area();
impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle { width: size, height: size, } } } let rect3 = Rectangle::square(30);
let v: Vec<i32> = Vec::new(); let v = vec![1,2,3,4,5]; let third: &i32 = &v[2]; //crashes for non-existent index match v.get(2) { // can handle non-existent index Some(el) => println!("Third elem is: {}", el), None => println!("There is no third elem."), }
To change the value of the vector in the loop we have to dereference it
let mut v = vec![100, 32, 57]; for i in &mut v { *i += 50; }
let my_closure = |x| { x+1 }; my_closure(5); // types of closure automatically inferred by the compiler let my_closure2 = |x: u32| -> u32 { x +1}; // explicit type annotations
Technique where we execute expensive closure and hold resulting value for the future so we would not need to evaluate the closure again.
struct Cacher<T> where T: Fn(u32) -> u32, { calculation: T, value: Option<u32>, } impl<T> Cacher<T> where T: Fn(u32) -> u32, { fn new(calculation: T) -> Cacher<T> { Cacher { calculation, value: None, } } fn value(&mut self, arg: u32) -> u32 { match self.value { Some(v) => v, None => { let v = (self.calculation)(arg); self.value = Some(v); v } } } }
fn main() { let mut my_closure = Cacher::new(|x: u32| x + 1); println!("{}", my_closure.value(10)); // calculates for the first time println!("{}", my_closure.value(10)); // uses stored value }