Skip to content

Instantly share code, notes, and snippets.

@choonkeat
Last active February 24, 2023 04:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save choonkeat/a7964d16744deb729ecb5ae103e29947 to your computer and use it in GitHub Desktop.
Save choonkeat/a7964d16744deb729ecb5ae103e29947 to your computer and use it in GitHub Desktop.

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day1/looper/src/main.rs#L9

for n in 0..10 { // 0,1,2,3,4,5,6,7,8,9
let v = vec![4,7,8,9,11,14]
for n in &v {

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day1/looper/src/main.rs#L18-L21

'outer: for i in 1..10 {
    for n in &v {
        if i+n ==11  {
            break 'outer;
        }

break to label

let s = "hello"

s is of type &str

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/b149362c82ade9e40096ed5c8e01b461863fc305/day1/assignment1/src/main.rs#L6-L9

match c {
    'w'|'W'=> println!("Hello {}", a),
    _=>{}
}

Rust is imperative, and you can "do nothing" with {}

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/b149362c82ade9e40096ed5c8e01b461863fc305/day1/enums/src/main.rs#L20-L22

let t = Lounge(5,"big".to_string());

match t {
    Kitchen(_i) -> {}
    Bedroom(_b) -> {}
    Lounge(n, s) -> println!("Its a {} lounge with {} cupboards",s,n);
}

match is exhaustive.

if let Lounge(n,s) = t {
    println!("Its a {} lounge with {} cupboards",s,n);
}

All the pattern matching are https://doc.rust-lang.org/reference/patterns.html

But if let let us only do something when an Enum value is of a particular Variant

let inside = drink.unwrap();

unwrap causes a panic when it receives a None; see also unwrap_or_else

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/intro/src/main.rs#L12

fn add(self,other:Point)->Self

Self is the type of self

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/randuser/Cargo.toml#L7 https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day4/ass_5/Cargo.toml#L9

rand = "0.5.5"
money_typesafe = {path = "../../day2/ass_10/"}

Specify dependencies for 3rd party package rand and local package money_typesafe

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/randuser/src/main.rs#L1-L3

extern crate rand;

use rand::Rng;

1 declaration to import package to file. 1 declaration to use what from the package.

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/randuser/src/main.rs#L14-L15 https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/randuser/src/main.rs#L40

impl Point{
    fn random()->Self{}
}

let d = Point::random();

defining a function namespaced under a type.. with "convenience" of referring to Self instead of the type name, Point? but when first argument is self, it's actually a method

impl<T> LinkedList<T>{
    pub fn new(t:T)->Self{
        Head(t,Box::new(Tail))
    }
    pub fn push(self,t:T)->Self {    // note `self` argument is not borrowed &self, it is _moved_
        Head(t,Box::new(self))
    }
}

let mut l = LinkedList::new(3);
l.push(4);

note ☝️ that we cannot use l anymore after calling push on it

error[E0382]: use of moved value: `l`
  --> src/lib.rs:44:9
   |
42 |         let mut l = LinkedList::new(3);
   |             ----- move occurs because `l` has type `LinkedList<i32>`, which does not implement the `Copy` trait
43 |         l.push(4);
   |           ------- `l` moved due to this method call
44 |         l.push(7);
   |         ^ value used here after move
   |
note: this function takes ownership of the receiver `self`, which moves `l`
  --> src/lib.rs:19:17
   |
19 |     pub fn push(self,t:T)->Self {
   |                 ^^^^

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/exchange/src/lib.rs#L49-L52

cargo test to run tests

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let g = GBP(200);
        let ex = Ex{cad:0.7,gbp:1.3};
        let c:CAD = ex.convert(g);

        assert_eq!(c, CAD(371));
    }
}

note that to use assert_eq, the values must derive PartialEq and Debug

#[derive(PartialEq,Debug)]
pub struct CAD (i32);

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/doc_9/src/lib.rs#L23-L29

/// Parse your money from a string
/// ``` 
/// use doc_9_testing_12345::*;
/// let g = "£32.45".parse(); 
/// assert_eq!(g,Ok(GBP(3245)));
///
/// ```
#[derive(Debug,PartialEq)]
pub struct GBP(pub i32);

doc tests to replace original test mod

cargo new --lib {package name} to generate a new library project cargo doc to generate documentation, and you can view it with open target/doc/{package name}/index.html

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/exchange/src/lib.rs#L9-L26

pub trait ToUSDv<F>{
pub struct Ex { ... }
impl ToUSDv<GBP> for Ex { ... }

implementing Traits

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/ass_10/src/currencies.rs#L32-L34

pub trait Currency{
    fn symbol()->char { '$' }
    fn decimal_point()->usize{ 2 } 

your trait can come with default implementation, optionally overwritten during impl

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/exchange/src/lib.rs#L35-L45

pub trait Exchange<F,T> { ... }
impl<E,F,T> Exchange<F,T> for E where E:ToUSDv<F> + FromUSDv<T> { ... }

generic traits

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/t_pool_4/src/main.rs#L11

impl<F:FnOnce()> FnBox for F{

means we've implemented the trait for all that has FnOnce() trait..

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/transaction/src/lib.rs#L28-L32

pub struct Transaction<A>{
    from_id:i32,
    to_id:i32,
    amount:A,
}

generic struct

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/iterators/src/lib.rs#L68

|acc,x| acc + x // is like (acc,x) => acc + x

anonymous function syntax

https://github.com/pretzelhammer/rust-blog/blob/master/posts/tour-of-rusts-standard-library-traits.md

Tour of Rust's Standard Library Traits

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/from_8/src/lib.rs#L25-L26

fn from_str(s:&str)->Result<Self,Self::Err>{
    Ok(GBP(parse_sym_money(s,'£',2)?))

the ? means early return on Err. the fact that there's Ok means

let x = number42?

the code either return Err or assign x = 42. note that it isn't x = Ok(42)

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day2/from_8/src/lib.rs#L14-L18

impl From<ParseMoneyError> for GBPError {
    fn from(p:ParseMoneyError)->Self{
        GBPError::ParseError(p)
    }
}

convert value from one type into another. i guess it's super handy for ? return error type to conveniently convert upwards

Lifetimes

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day3/pass_through_2/src/lib.rs#L2

pub fn trim_left<'a,'b>(s:&'a str, t: &'b str)->&'a str { s }

// or

pub fn trim_left<'a>(s:&str, t: &'a str)->&'a str { t }

ok 👌

pub fn trim_left<'a,'b>(s:&'a str, t: &'b str)->&'a str { t }
7 | pub fn trim_left<'a,'b>(s:&'a str, t: &'b str)->&'a str { t }
  |                  -- -- lifetime `'b` defined here         ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
  |                  |
  |                  lifetime `'a` defined here
  |
  = help: consider adding the following bound: `'b: 'a`
pub fn trim_left(s:&str, t: &str)->&str { t }
7 | pub fn trim_left(s:&str, t: &str)->&str { t }
  |                    ----     ----   ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `s` or `t`
help: consider introducing a named lifetime parameter
  |
7 | pub fn trim_left<'a>(s:&'a str, t: &'a str)->&'a str { t }
  |                 ++++    ++          ++        ++

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day4/env_1/src/lib.rs#L1-L6

use std::env::{var,set_var};

pub fn road_len()->usize{
    let e = var("ROAD").unwrap_or("".to_string());
    e.len()
}

reading env

https://doc.rust-lang.org/std/process/struct.Command.html#method.new https://doc.rust-lang.org/std/process/struct.Command.html#method.arg

pub fn new<S: AsRef<OsStr>>(program: S) -> Command
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command

new returns Command and method arg returns &mut Command... for some reason it means this is ok:

let mut c = Command::new("ls");
                .arg("-l");
                .output()
                .expect("LS Not useable");

but this is not ok:

let mut c = Command::new("ls");
                .arg("-l");
let mut c = c.output()
                .expect("LS Not useable");
error [E0597]: borrowed value does not live long enough
  --> src/main.rs:4:13
   |
4  |     let c = Command: :new("ls")
   |             ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
5  |                 .arg("-l");
   |                           - temporary value dropped here while still borrowed
...
15 | }
   | - temporary value needs to live until here

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day4/files_4/src/main.rs

read from file -> string -> write into file

without f.read_to_string + restore copy(&mut f,&mut t)?; would've done the same without needing s variable

note that https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day4/files_4/src/main.rs#L2 we need to declare the traits that we are using, even though we don't mention them anywhere

use std::io::{Read,Write,copy};

otherwise we cannot read or write

https://doc.rust-lang.org/std/string/struct.String.html#method.into_bytes

pub fn into_bytes(self) -> Vec<u8, Global>

string.into_bytes just returns the Vec bytes already held, no copying was done to "convert"

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/split_1/src/main.rs#L18

spawn to kick off an async function, join will wait for that async to be done and return a Result 🤩 https://doc.rust-lang.org/std/thread/fn.spawn.html

|a,b| {
    return 5
}

anonymous function looks like Ruby's...

|| {
    return 5
}

but weird when there is no params

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/chan_2/src/main.rs#L2

mpsc refers to multiple producer, single consumer

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/chan_2/src/main.rs#L7

let (cs,cr) = mpsc::channel::<i32>();

channel send, channel receive = channel ...

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/chan_2/src/main.rs#L8

    let (cs,cr) = mpsc::channel::<i32>();
    let h = spawn(move||{
        loop {
            match cr.recv() {
                Ok(v) => {

the move|| means any variable we use in the closure is moved, e.g. cr

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/chan_2/src/main.rs#L34

    let (cs,cr) = mpsc::channel::<i32>();
    ...
    drop(cs)

when we cs variable goes out of scope, dropped, then cr will close, causing the spawn process to terminate with Err on cr.recv()

note that drop function is effectively only

fn drop(&mut self) {}

by using the rust linear type system, simply moving the pointer to the function and not returning it, variable cs goes out of scope 🎤 drop

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/mutex_3/src/main.rs#L9-L19

    let m = Arc::new(Mutex::new(32));

    let mut handles = Vec::with_capacity(10);
    for i in 0..10 {
        let am = m.clone(); // cloning the Arc

Invoking clone on Arc produces a new Arc instance, which points to the same allocation on the heap as the source Arc, while increasing a reference count. When the last Arc pointer to a given allocation is destroyed, the value stored in that allocation (often referred to as “inner value”) is also dropped. https://doc.rust-lang.org/std/sync/struct.Arc.html

        let j = i;
        handles.push(spawn(move ||{
            let mut p = am.lock().unwrap(); // locking the Mutex; though `am` is Arc, when calling methods it passes through
            *p += j;
            println!("j = {} , p = {}" ,j,*p);

Acquires a mutex, blocking the current thread until it is able to do so. https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.lock

using the type system, the Mutex library makes impossible to get to the value protected by mutex without calling lock on it.

https://github.com/PacktPublishing/-Learn-Rust-in-7-Days/blob/f2a59262ace5e52f16c88dcd63918ca0c0b5a903/day5/t_pool_4/src/main.rs#L36

- let job = match amp.lock().unwrap().recv() {
+ let lck = amp.lock().unwrap();
+ let job = match lck.recv() {
        Ok(j) => j,
        _ => return,
  };
  job.call_box();

will be slower because lck is still in scope and remains locked until AFTER a potentially long running job.call_box() is done.

in the original code, the lock is immediately out of scope after calling recv(), thus lock is released and other threads could grab it without waiting for a potentially long running job.call_box() to finish

Just use https://docs.rs/rayon/latest/rayon/ which

give you access to the par_iter method which provides parallel implementations of many iterative functions such as map, for_each, filter, fold, and more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment