====== 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
}