====== Rust ====== ===== Resources ===== * [[https://fasterthanli.me/blog/2020/a-half-hour-to-learn-rust/|Half an hour to learn Rust]] * [[https://cheats.rs/|Rust Cheat Sheet]] ===== General ===== Rust uses snake case convention: * functions and variables all lower case with _ separating words * function parenthesis after function name 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 ===Attributes=== #[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 ===== cargo new PROJECT_NAME (--bin/lib) cargo build --release cargo run cargo update cargo doc --open ===== Diesel ===== [[https://diesel.rs/|Docs]] 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 { ... } ===== Data Types ===== === Integers === (signed ''i8'', unsigned ''u8'') (''isize'' defaults to your computer architecture 32/64 bit) * ''i8'', ''i16'', ''i32'', ''i64'', ''i128'', ''isize'' * Default: ''i32'' even on 64 bit machines === Floating-Point === * ''f32''(single precision), ''f64''(double precision) * Default: ''f64'' === Character === * ''char'' specified with single quotes ''let c = 'z' '' * four bytes (Unicode - Chinese, Japanese, Korean, Emoji) === Tuple === fn main() { let tup: (i32, f64, u8) = (500, 6.4, 1); let (x, y, z) = tup; let five_hundred = tup.0; } * Fixed length structure holding multiple values * Allows destructuring * Can hold different data types === Array === * Holds same type of elements * Fixed length 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 ===== Functions ===== Function bodies are made of statements and optionally end with an expression. * Statements do not return values ''let x = 3;'' * Expressions return values ''4+6'' * Expressions can be start of statements ''let x = 4+6;'' * Calling a function/macro is an expression * Expressions do not end with '';'', adding semicolon will turn it into statement which will not return value fn five() -> i32 { 5 } fn main() { let x = five(); println!("The value of x is: {}", x); } === Tuples === let rect1 = (30, 50); fn area(dimensions: (u32, u32)) -> u32 { dimensions.0 * dimensions.1 } ===== Control Flow ===== 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'' === Loop === 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); } === While === fn main() { let mut number = 3; while number != 0 { println!("{}!", number); number -= 1; } println!("LIFTOFF!!!"); } === For === fn main() { let a = [10, 20, 30, 40, 50]; for element in a.iter() { println!("the value is: {}", element); } } ===== Structs ===== 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 } === Tuple Structs === struct Color(i32, i32, i32); struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0); === Implementing methods === impl Rectangle { fn area(&self) -> u32 { self.height * self.height } } let area = rect1.area(); === Implementing namespaces === impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle { width: size, height: size, } } } let rect3 = Rectangle::square(30); ===== Collections ===== ===Vector=== let v: Vec = 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; } =====Closures===== 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 ===Memoization / lazy evaluation=== 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 where T: Fn(u32) -> u32, { calculation: T, value: Option, } impl Cacher where T: Fn(u32) -> u32, { fn new(calculation: T) -> Cacher { 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 }