├── rpl ├── _04_basics │ ├── README.md │ ├── types │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ ├── branches │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ └── variables │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ └── main.rs ├── _02_hello_cargo │ ├── src │ │ └── main.rs │ ├── Cargo.lock │ ├── README.md │ └── Cargo.toml ├── _06_structs │ ├── Cargo.toml │ ├── Cargo.lock │ └── src │ │ └── main.rs ├── _08_enums │ ├── Cargo.toml │ ├── Cargo.lock │ └── src │ │ └── main.rs ├── _09_match │ ├── Cargo.toml │ ├── Cargo.lock │ └── src │ │ └── main.rs ├── _07_methods │ ├── Cargo.toml │ ├── Cargo.lock │ └── src │ │ └── main.rs ├── _10_packages │ ├── Cargo.toml │ ├── Cargo.lock │ └── src │ │ └── lib.rs ├── _05_ownership │ ├── _03_move │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ ├── _01_scope │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ ├── _02_string │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ ├── _04_funcs │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ ├── _06_dangling │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ ├── _07_slices │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ │ └── main.rs │ └── _05_references │ │ ├── Cargo.toml │ │ ├── Cargo.lock │ │ └── src │ │ └── main.rs ├── _11_collections │ ├── Cargo.toml │ ├── Cargo.lock │ ├── exercises │ │ ├── exercise_1_solution │ │ │ ├── Cargo.toml │ │ │ ├── Cargo.lock │ │ │ └── src │ │ │ │ └── main.rs │ │ ├── exercise_2_solution │ │ │ ├── Cargo.toml │ │ │ ├── Cargo.lock │ │ │ └── src │ │ │ │ └── main.rs │ │ └── README.md │ └── src │ │ ├── main.rs │ │ ├── vectors.rs │ │ ├── hashmaps.rs │ │ └── strings.rs ├── _06_structs_example │ ├── Cargo.toml │ ├── Cargo.lock │ └── src │ │ └── main.rs ├── _03_guessing_game │ ├── README.md │ ├── Cargo.toml │ ├── src │ │ ├── _naked.rs │ │ └── main.rs │ └── Cargo.lock └── _01_hello │ └── main.rs ├── notes ├── langs.png ├── useless.md ├── glossary.md ├── install.md ├── mechanics.md ├── shocks.md ├── faq.md ├── tips.md ├── rustbook.md └── resources.md ├── .gitignore └── README.md /rpl/_04_basics/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /notes/langs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inancgumus/learnrust/HEAD/notes/langs.png -------------------------------------------------------------------------------- /rpl/_02_hello_cargo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /rpl/_06_structs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "structs" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_08_enums/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_01_basics" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_09_match/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_09_match" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_04_basics/types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "types" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_07_methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_07_methods" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_10_packages/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_10_packages" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_04_basics/branches/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "branches" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_04_basics/variables/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "variables" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_03_move/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_03_move" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_11_collections/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_11_collections" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_01_scope/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ownership" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_02_string/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_02_string" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_04_funcs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_04_funcs" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_06_dangling/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dangling" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_07_slices/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_07_slices" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_08_enums/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_01_basics" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | main.dSYM/ 3 | 4 | # Generated by Cargo 5 | # will have compiled files and executables 6 | target/ 7 | 8 | # These are backup files generated by rustfmt 9 | **/*.rs.bk -------------------------------------------------------------------------------- /rpl/_04_basics/types/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "types" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_05_references/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "references" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_06_structs/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "structs" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_06_structs_example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "_06_structs_example" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_07_methods/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_07_methods" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_09_match/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_09_match" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_10_packages/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_10_packages" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /rpl/_02_hello_cargo/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "hello-cargo" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_04_basics/branches/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "branches" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_04_basics/variables/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "variables" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_01_scope/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ownership" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_03_move/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_03_move" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_04_funcs/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_04_funcs" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_11_collections/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_11_collections" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_02_string/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_02_string" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_06_dangling/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "dangling" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_07_slices/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_07_slices" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_05_references/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "references" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_06_structs_example/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "_06_structs_example" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_11_collections/exercises/exercise_1_solution/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "exercise_1_solution" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_11_collections/exercises/exercise_2_solution/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "exercise_2_solution" 3 | version = "0.1.0" 4 | authors = ["Inanc Gumus "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /rpl/_11_collections/exercises/exercise_1_solution/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "exercise_1_solution" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_11_collections/exercises/exercise_2_solution/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "exercise_2_solution" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /rpl/_03_guessing_game/README.md: -------------------------------------------------------------------------------- 1 | # Guessing Game 2 | 3 | 1. First, we add a dependency named `rand` to [Cargo.toml](Cargo.toml) file. 4 | 5 | 2. Then you can start coding in [src/main.rs](src/main.rs). Read this for the explanations. 6 | 7 | 3. For the drier version (_without annotations_), see [this one](src/_naked.rs). -------------------------------------------------------------------------------- /notes/useless.md: -------------------------------------------------------------------------------- 1 | # Useless Knowledge 2 | 3 | ## Rust's name? 4 | 5 | Graydon is Rust's creator. 6 | 7 | I think I named it after fungi. rusts are amazing creatures. 8 | Five-lifecycle-phase heteroecious parasites. I mean, that’s just _crazy_. 9 | talk about over-engineered for survival 10 | -------------------------------------------------------------------------------- /rpl/_03_guessing_game/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "guessing_game" 4 | version = "0.1.0" 5 | authors = ["Inanc Gumus "] 6 | edition = "2018" 7 | 8 | # A crate is a collection of Rust source code files. 9 | 10 | # - we can't generate random nums using stdlib. 11 | # + let's include the rand crate as a dependency. 12 | # this way, we can generate random numbers. 13 | [dependencies] 14 | rand = "0.7.3" -------------------------------------------------------------------------------- /rpl/_05_ownership/_06_dangling/src/main.rs: -------------------------------------------------------------------------------- 1 | // Dangling References 2 | // Rust never gives you a dangling pointer. 3 | 4 | fn main() { 5 | // let refToNothing = dangle(); 6 | // -> think about using the null pointer here! CRASH! 7 | } 8 | 9 | /* 10 | fn dangle() -> &String { // returns a ref to a String 11 | let s = String::from("hello"); 12 | &s // return a ref to s 13 | } // but s drops! 14 | */ 15 | 16 | fn _safe() -> String { 17 | let s = String::from("hello"); 18 | s 19 | } -------------------------------------------------------------------------------- /notes/glossary.md: -------------------------------------------------------------------------------- 1 | # Glossary 2 | 3 | | term | explanation | 4 | | ---- | ----------- | 5 | | ahead-of-time compilation | compiling beforehand | 6 | | binary executable | a file that a computer already understands | 7 | | cargo | Rust’s official build system and package manager | 8 | | crate | a bundle of code that you can use in your project | 9 | | crates.io | the official Rust package registry | 10 | | drop | automatically freeing memory for a variable or other resource | 11 | | macro | it’s like a global function | 12 | | rustacean | a Rust community member | 13 | | rustup | the official Rust version manager | 14 | | turbofish | `::` lets you explicitly specify the type | 15 | | wasm | Web Assembly | -------------------------------------------------------------------------------- /rpl/_05_ownership/_01_scope/src/main.rs: -------------------------------------------------------------------------------- 1 | // OWNERSHIP 2 | // 3 | // MAIN IDEA: 4 | // 5 | // "SCOPE owns a VARIABLE owns a VALUE" 6 | // 7 | // + A value lives on memory. 8 | // + It can move between variables. 9 | // + A variable can be an owner of a value. 10 | // + A variable comes in and goes out of a scope. 11 | // 12 | // RULES: 13 | // + Each value has a single owner. 14 | // + Ownership can move between variables. 15 | // + When the owner goes out of scope, the value will be dropped. 16 | 17 | fn main() { 18 | scope(); 19 | } 20 | 21 | fn scope() { // s isn't declared yet. not valid here. 22 | let s = "hi"; // s comes into scope here. 23 | 24 | println!("{}", s); // work with s however you want. 25 | 26 | } // s goes out of scope. 27 | // you can no longer use it. 28 | -------------------------------------------------------------------------------- /rpl/_02_hello_cargo/README.md: -------------------------------------------------------------------------------- 1 | # First Cargo Program 2 | 3 | * You can create a similar directory by typing: 4 | 5 | ```bash 6 | cargo new _02_hello_cargo 7 | ``` 8 | 9 | * This command creates a [Cargo.toml](Cargo.toml) file, click on the link at the left to learn more about it. 10 | 11 | * Then, start writing code in [src/main.rs](src/main.rs). 12 | 13 | * Cargo uses Cargo.lock file to fix the crate versions (aka: _package in other langs_). It is idiomatic to save this file to [git](https://git-scm.com/) for executable programs. Otherwise, if you're building a rust library, then add this to your `.gitignore`. To learn why, [read this](https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries). 14 | 15 | * See [this](/notes/tips.md#cargo) to understand how to run a program using Cargo. 16 | 17 | --- 18 | 19 | 👉 You can also read more about Cargo [here](https://doc.rust-lang.org/cargo/). -------------------------------------------------------------------------------- /rpl/_04_basics/variables/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x = 5; 3 | println!("x: {}", x); 4 | 5 | // x variable is immutable. 6 | // so we can't change its value. 7 | // x = 6; 8 | 9 | // but we can declare a new variable, 10 | // with the same name: `x`. 11 | // 12 | // this way, we don't need to imagine 13 | // new variable names. 14 | let x = 6; 15 | println!("x: {}", x); 16 | 17 | // we can also create a constant. 18 | // constant are compile-time values. 19 | // so, anywhere MAX_VALUE appears, the 20 | // compiler will change it with 10 instead. 21 | // 22 | // instead of using hardcoded values, use 23 | // constants instead. 24 | const MAX_VALUE: u32 = 10; 25 | println!("MAX_VALUE: {}", MAX_VALUE); 26 | 27 | // SHADOWING 28 | let spaces = " "; // &str 29 | let spaces = spaces.len(); // usize 30 | println!("spaces: {}", spaces); 31 | } 32 | -------------------------------------------------------------------------------- /rpl/_02_hello_cargo/Cargo.toml: -------------------------------------------------------------------------------- 1 | # toml = Tom's obvious, minimal language 2 | # toml is Cargo's configuration format. 3 | # this is where you specify details about your package. 4 | 5 | # see more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6 | 7 | [package] 8 | name = "hello-cargo" # what's the name of this package? 9 | version = "0.1.0" # what's the version of this package? 10 | authors = ["Inanc Gumus "] # who wrote this package? 11 | edition = "2018" # rust edition 12 | # see: https://doc.rust-lang.org/edition-guide/editions/index.html 13 | 14 | # this package doesn't depend on other packages (crates), 15 | # so this is empty. 16 | [dependencies] 17 | 18 | # Use these settings for optimized output 19 | 20 | # [profile.release] 21 | # opt-level = 'z' # Optimize for size. 22 | # lto = true # Enable Link Time Optimization 23 | # codegen-units = 1 # Reduce number of codegen units to increase optimizations. 24 | # panic = 'abort' # Abort on panic -------------------------------------------------------------------------------- /rpl/_11_collections/src/main.rs: -------------------------------------------------------------------------------- 1 | // https://doc.rust-lang.org/std/collections/index.html 2 | 3 | mod vectors; // make vectors.rs act like the vectors module. 4 | 5 | mod strings; // make strings.rs act like the strings module. 6 | 7 | mod hashmaps; // make hashmaps.rs act like the hashmaps module. 8 | 9 | fn main() { 10 | println!("*******************************************************************"); 11 | println!("★ VECTORS ★"); 12 | println!("*******************************************************************"); 13 | vectors::run(); 14 | println!("\n"); 15 | println!("*******************************************************************"); 16 | println!("★ STRINGS ★"); 17 | println!("*******************************************************************"); 18 | strings::run(); 19 | println!("\n"); 20 | println!("*******************************************************************"); 21 | println!("★ HASH MAPS ★"); 22 | println!("*******************************************************************"); 23 | hashmaps::run(); 24 | } 25 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_02_string/src/main.rs: -------------------------------------------------------------------------------- 1 | // "hi earthlings" 2 | // -> This is a string literal. 3 | // -> Its value is known at compile-time. 4 | // -> Rust hardcodes it into the final executable. 5 | // 6 | // String::from("hi"); 7 | // -> This is a String. 8 | // -> Its value is only known in runtime. 9 | // -> It can dynamically change in runtime. 10 | // -> Rust allocates it on the HEAP memory. 11 | 12 | // For heap allocated values, Rust needs to manage 13 | // them somehow. When they're no longer needed, 14 | // it should clean them from memory (to drop'em). 15 | fn main() { 16 | let mut s = String::from("hi"); // s comes into the scope 17 | // its data is allocated on the heap 18 | 19 | s.push_str(", earthlings!"); // change the s 20 | 21 | println!("{}", s); // print the s 22 | 23 | } // s goes out of scope 24 | // Rust calls the drop fn on s 25 | // that returns the memory used by s 26 | // back to OS 27 | -------------------------------------------------------------------------------- /rpl/_03_guessing_game/src/_naked.rs: -------------------------------------------------------------------------------- 1 | use rand::Rng; 2 | use std::cmp::Ordering::*; 3 | use std::io; 4 | use std::io::Write; 5 | 6 | fn main() { 7 | let secret = rand::thread_rng() 8 | .gen_range(1, 101); 9 | 10 | loop { 11 | print!("guess: "); 12 | io::stdout() 13 | .flush() 14 | .expect("🤬 cannot flush"); 15 | 16 | let mut guess = String::new(); 17 | io::stdin() 18 | .read_line(&mut guess) 19 | .expect("🤬 cannot read input"); 20 | 21 | let guess: u32 = match guess.trim().parse() { 22 | Ok(n) => n, 23 | Err(_) => { 24 | println!("🤬 not a number"); 25 | continue; 26 | } 27 | }; 28 | println!("you say: {}, let's see...", guess); 29 | 30 | match guess.cmp(&secret) { 31 | Less => println!("🤨 bigger"), 32 | Greater => println!("🤨 smaller"), 33 | Equal => { 34 | println!("🥳 you rock!"); 35 | break; // exit the loop 36 | } 37 | } 38 | println!(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /notes/install.md: -------------------------------------------------------------------------------- 1 | # Install Rust 2 | 3 | ## Installing manually 4 | 5 | * I recommend you to use `rustup` (instructions below). 6 | * If you want to do it the hard way—manually—see [this](https://www.rust-lang.org/tools/install/) 7 | 8 | 9 | ## rustup 10 | * Use this one to install any Rust version. 11 | `curl https://sh.rustup.rs -sSf | sh` 12 | 13 | * You can even uninstall Rust: 14 | `rustup self uninstall` 15 | 16 | * Let's see the Rust documentation offline: 17 | `rustup doc` 18 | 19 | * You can update to a newer Rust version (*if you'd like*): 20 | `rustup update` 21 | 22 | 23 | ## Solutions to possible problems 24 | 25 | ### VSCode integration problems 26 | * **If you see these errors:** 27 | * Couldn't start client Rust Language Server. 28 | * Rustup not available. 29 | * **Add this to your config:** 30 | ```json 31 | "rust-client.rustupPath": "~/.cargo/bin/rustup", 32 | ``` 33 | 34 | ### Toolchain running problems 35 | * **If you see the error when running `cargo` on OS X:** 36 | * `"Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib" cargo` 37 | * **Change your OpenSSL version:** 38 | ```bash 39 | brew switch openssl 1.0.2r 40 | ``` -------------------------------------------------------------------------------- /rpl/_11_collections/exercises/README.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | 👉 [Click to see the solutions](.). 4 | 5 | ## Exercise 1 6 | 7 | You have given a list of integers. 8 | 9 | 1. Use a vector and return the mean (the average value). 10 | 2. Return the median (_when sorted, the value in the middle position_). 11 | 3. Return the mode (_the value that occurs most often; a hash map will be helpful here_) of the list. 12 | 13 | ## Exercise 2 14 | 15 | Convert strings to pig latin (_Keep in mind the details about UTF-8 encoding!_). 16 | 17 | -> The first consonant of each word is moved to the end of the word and "ay" is added: 18 | 19 | "first" becomes "irst-fay" 20 | 21 | -> Words that start with a vowel have "hay" added to the end instead: 22 | 23 | "apple" becomes "apple-hay" 24 | 25 | ## Exercise 3 26 | 27 | Using a `hash map` and `vectors`, create a text interface to allow a user to add employee names to a department in a company. 28 | 29 | * For example, "Add Sally to Engineering" or "Add Amir to Sales." 30 | * Then let the user retrieve a list of all people in a department 31 | * Or all people in the company by department, sorted alphabetically. 32 | 33 | --- 34 | _Exercises are copied from the original Rust book [here](https://doc.rust-lang.org/nightly/book/ch08-03-hash-maps.html)._ -------------------------------------------------------------------------------- /rpl/_04_basics/branches/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // if expressions 3 | let number = 5; 4 | if number == 5 { 5 | println!("number is 5"); 6 | } else if number == 4 { 7 | println!("number is 4"); 8 | } else { 9 | println!("number is not 5"); 10 | } 11 | 12 | // let + if 13 | let on = true; 14 | let n = if on { 1 } else { 0 }; 15 | println!("n: {}", n); 16 | 17 | // loops 18 | let mut i = 0; 19 | loop { 20 | println!("is universe infinite?"); 21 | i += 1; 22 | if i == 2 { 23 | break; 24 | } 25 | } 26 | 27 | // loop expressions 28 | let mut counter = 0; 29 | let result = loop { 30 | counter += 1; 31 | 32 | if counter == 2 { 33 | break counter + 1; 34 | } 35 | }; 36 | println!("result: {}", result); 37 | 38 | // while loops 39 | let mut number = 3; 40 | while number != 0 { 41 | println!("{}!", number); 42 | number -= 1; 43 | } 44 | println!("LIFTOFF!!!"); 45 | 46 | // for loops 47 | let a = [1; 3]; 48 | for e in a.iter() { 49 | println!("e: {}", e); 50 | } 51 | 52 | // rev() 53 | for n in (1..4).rev() { 54 | println!("{}!", n) 55 | } 56 | println!("boom!") 57 | } 58 | -------------------------------------------------------------------------------- /notes/mechanics.md: -------------------------------------------------------------------------------- 1 | # Mechanics 2 | 3 | ## Error Handling 4 | 5 | * Rust has a built in generic enum called Result. 6 | * It allows us to return a value that has the possibility of failing. 7 | * It is the idiomatic way in which the language does error handling. 8 | 9 | ```rust 10 | enum Result{ 11 | Ok(T), 12 | Err(Q) 13 | } 14 | ``` 15 | 16 | ### Example: 17 | 18 | ```rust 19 | fn might_fail(i:i32) -> Result { 20 | if i == 42 { 21 | Ok(13.0) 22 | } else { 23 | Err(String::from("this is not the right number")) 24 | } 25 | } 26 | ``` 27 | 28 | #### Verbose Way: 29 | 30 | ```rust 31 | fn main() { 32 | let result = do_something_that_might_fail(12); 33 | match result { 34 | Ok(v) => println!("found {}", v), 35 | Err(e) => println!("Error: {}",e), 36 | } 37 | } 38 | ``` 39 | 40 | #### Concise Way: 41 | 42 | ```rust 43 | fn main() -> Result<(), String> { 44 | let v = do_something_that_might_fail(42)?; 45 | println!("found {}", v); 46 | Ok(()) 47 | } 48 | ``` 49 | 50 | #### Bad Way: 51 | 52 | **Don't use `unwrap()`.** 53 | 54 | ```rust 55 | fn main() -> Result<(), String> { 56 | // concise but assumptive and gets ugly fast 57 | let v = do_something_that_might_fail(42)?; 58 | println!("found {}", v); 59 | 60 | // this will panic! 61 | let v = do_something_that_might_fail(1)?; 62 | println!("found {}", v); 63 | 64 | Ok(()) 65 | } 66 | ``` 67 | 68 | --- -------------------------------------------------------------------------------- /notes/shocks.md: -------------------------------------------------------------------------------- 1 | # Shocks 2 | 3 | Weird Rust stuff documented. 4 | 5 | 1. **There is no null in Rust!** 6 | 7 | Instead, there is `None`, and there is: 8 | 9 | ```rust 10 | enum Option{ 11 | Some(T), 12 | None 13 | } 14 | ``` 15 | 16 | 2. **String `AsRef`** 17 | 18 | Why the heck `String` has a responsibility for `Path`... 19 | 20 | 3. **Why Rust doesn't allow marking only some struct fields mutable?** 21 | 22 | Each field is in a different memory location. However, the struct 23 | is a type. So, when using it, we can't know which part of the 24 | struct's instance that the other code is going to use. 25 | 26 | 4. **I couldn't grasp how to run multiple files together from get-go** 27 | 28 | src/main.rs: 29 | 30 | ```rust 31 | mod vectors; 32 | fn main() { 33 | vectors::run_vectors(); 34 | } 35 | ``` 36 | 37 | src/vectors.rs: 38 | 39 | ```rust 40 | pub fn run_vectors() { 41 | println!("vectors!"); 42 | } 43 | ``` 44 | 45 | 👉 [See this for the best explanation](https://learning-rust.github.io/docs/d3.modules.html). 46 | 47 | 5. **String concatenation uses the buffer of the origin string** 48 | 49 | This is a good thing as in the op below, Rust will copy str2 to 50 | str1's buffer. 51 | 52 | ```rust 53 | let str3 = str1 + &str2; 54 | ``` 55 | 56 | 6. **People can add their own hashers to stdlib's HashMap implementation** 57 | 58 | Check out them [here](https://crates.io/search?q=hasher). -------------------------------------------------------------------------------- /notes/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | * [Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?](https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-to-a-string-string-vec-vec-o) 4 | * To allow more generic code. 5 | 6 | * [What are the differences between `String` and `str`?](https://stackoverflow.com/questions/24158114/what-are-the-differences-between-rusts-string-and-str) 7 | * `String` is the dynamic heap string type, like Vec: use it when you need to own or modify your string data. 8 | * `str` is an immutable sequence of UTF-8 bytes of dynamic length somewhere in memory. Since the size is unknown, one can only handle it behind a pointer. This means that str most commonly2 appears as &str: a reference to some UTF-8 data, normally called a "string slice" or just a "slice". 9 | * Use `String` if you need owned string data (_like passing strings to other threads, or building them at runtime_), and use `&str` if you only need a view of a string. 10 | 11 | * [Why are explicit lifetimes needed in Rust?](https://stackoverflow.com/questions/31609137/why-are-explicit-lifetimes-needed-in-rust) 12 | * The main reason is that while the compiler can see what your code does, it doesn't know what your intent was. 13 | 14 | * [What is the difference between iter and into_iter?](https://stackoverflow.com/questions/34733811/what-is-the-difference-between-iter-and-into-iter) 15 | * `iter()` iterates over the items by _borrowing_. 16 | * `into_iter()` iterates over the items, _moving_ them into the new scope (_takes ownership_). 17 | * `iter_mut()` iterates over the items, giving a _mutable reference_ to each item. -------------------------------------------------------------------------------- /rpl/_11_collections/src/vectors.rs: -------------------------------------------------------------------------------- 1 | // ⭐️ A vector is stored on the heap memory. 2 | 3 | pub fn run() { 4 | // 5 | // let's create a vector of 32-bit ints: 6 | // __________/ 7 | // / 8 | let mut v: Vec = Vec::new(); 9 | // 10 | // let's create the same vector w/type-inferring: 11 | // 12 | // let v = vec![1, 2, 3]; 13 | // 14 | // let's create another i32 vector that looks like this: `[1, 1, 1]`. 15 | // 16 | // let v = vec![1; 3]; 17 | // 18 | 19 | // let's update the vector 20 | v.push(1); 21 | v.push(2); 22 | v.push(3); 23 | 24 | println!("\nreading a vector:"); 25 | println!("first : {}", &v[0]); 26 | println!("second: {}", v.get(1).unwrap()); // use this with `match`. 27 | 28 | // 29 | // Borrowing and Ownership: 30 | // 31 | // let first = &v[0]; // immutable borrow 32 | // v.push(4); // mutable borrow -> ERROR 33 | // println!("first: {}", first); // immutable borrow 34 | // 35 | // A vector can move its elements (behind the scenes). 36 | // That's why even borrowing the first element, then pushing 37 | // another one at the end can create an error here. 38 | // 39 | 40 | println!("\nwalking over a vector:"); 41 | for i in &mut v { 42 | // v is a Vec 43 | // i is a `&mut i32`, and `*i` is an i32. 44 | // Here, we're writing to the memory cell where i lives by dereferencing. 45 | *i *= 2; // write to the vector element 46 | 47 | println!("{}", i); // read the vector element 48 | } 49 | // To walk over immutably, use: 50 | // for i in &v {..} 51 | } 52 | // Rust will drop `v` here, along with its elements. 53 | -------------------------------------------------------------------------------- /rpl/_06_structs_example/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Rectangle { 2 | width: u32, 3 | height: u32, 4 | } 5 | 6 | fn main() { 7 | { 8 | let rect = Rectangle { 9 | width: 30, 10 | height: 50, 11 | }; 12 | println!( 13 | "The area of a {}x{} rectangle is {} pixels.", 14 | rect.width, 15 | rect.height, 16 | // area(rect), // this code is moving rect to area 17 | area(&rect), // but with this one, area is borrowing the rect 18 | ); 19 | // if the area didn't borrow the rect, 20 | // the main would never use it again. 21 | // println!("{}", rect.width); 22 | } 23 | println!(); 24 | // ---------------------------------------------------------------------- 25 | { 26 | // Rust provides a number of traits for us to use with the derive 27 | // annotation that can add useful behavior to our custom types. 28 | 29 | // DEBUGGING STRUCTS 30 | #[derive(Debug)] // With this Debug trait, println can print 31 | // an instance of the Rectangle struct. 32 | struct Rectangle { 33 | width: u32, 34 | height: u32, 35 | } 36 | 37 | let rect = Rectangle { 38 | width: 25, 39 | height: 15, 40 | }; 41 | 42 | println!("{:?}", rect); // You just need to use {:?} instead of {}. 43 | println!("{:#?}", rect); // Prettier output. 44 | } 45 | } 46 | 47 | // this function just immutably borrows a rectangle instance. 48 | // it doesn't own the instance. 49 | fn area(rectangle: &Rectangle) -> u32 { 50 | rectangle.width * rectangle.height 51 | } 52 | 53 | // this function signature is taking the ownership of a rectangle instance. 54 | // fn area(rectangle: Rectangle) -> u32 { 55 | // rectangle.width * rectangle.height 56 | // } 57 | -------------------------------------------------------------------------------- /rpl/_01_hello/main.rs: -------------------------------------------------------------------------------- 1 | /* 2 | #1: defines a function named: `main`. 3 | 4 | main function: 5 | + this is a special function. 6 | + it runs as the first code in an executable rust program. 7 | */ 8 | fn main() { 9 | /* ^ 10 | | 11 | between `{` and `}` 12 | 13 | this is where this function's body starts. 14 | 15 | ========================================================= 16 | COMPILING & RUNNING THIS PROGRAM: 17 | ========================================================= 18 | what you write in the function body will be executed, 19 | 20 | 1. when you compile: 21 | 22 | rustc main.rs 23 | 24 | 2. and run on xnix: 25 | 26 | ./main 27 | 28 | 3. or run on windows: 29 | 30 | .\main.exe 31 | */ 32 | 33 | println!("Hello, world!"); 34 | // ^ ^ 35 | /* | +--------------------------------------------------------+ 36 | | | 37 | #3: calls a macro named: `println` that writes "Hello, world!" to the screen. | 38 | | 39 | + to call a macro : println!("...") | 40 | + to call a function: println("...") | 41 | + you'll learn the differences later on. | 42 | | 43 | | 44 | end your statements with this semicolon. <----------------------------------------+ 45 | so the next one can begin. 46 | 47 | why? 48 | just like in C, and other languages with a similar syntax, 49 | semicolon here tells the compiler that this statement is over. 50 | */ 51 | } 52 | -------------------------------------------------------------------------------- /notes/tips.md: -------------------------------------------------------------------------------- 1 | # Tips 2 | 3 | 4 | ## General 5 | 6 | 1. Create SMALL rust binaries, see: [min-sized-rust](https://github.com/johnthagen/min-sized-rust). 7 | 2. Compile simple programs w/`rustc`, but larger programs w/`cargo`. 8 | 3. Format your code automatically: `rustfmt`. 9 | 10 | 11 | ## Cargo 12 | 13 | 1. Creates a new crate (it's like `go mod init`): 14 | 15 | `cargo new ` 16 | 17 | Without a git repository: 18 | 19 | `cargo new --vcs none` 20 | 21 | 2. Build the crate (it's like `go create`): 22 | 23 | `cargo build` 24 | 25 | `cargo b` 26 | 27 | 3. Run the crate (it's like `go run`): 28 | 29 | `cargo run` 30 | 31 | `cargo r` 32 | 33 | 1. Silently run: 34 | 35 | `cargo r -q` 36 | 37 | 4. Check whether your program can compile: 38 | 39 | `cargo check` 40 | 41 | `cargo c` 42 | 43 | Rustaceans use this command to periodically check their programs. After working on their program, and when they're sure, they build your program using `cargo build --release`. 44 | 45 | This command produces a faster program, but it'll take a longer time to compile. 46 | 47 | This is also the command you want to use when you benchmark your code. 48 | 49 | 5. Cargo caches. If you want to start on a clean slate, run: 50 | 51 | `cargo clean` 52 | 53 | Why? Sometimes, `cargo check` returns a warning. However, when you run it the second time, it doesn't display the warning. In that case, you can run `cargo clean`, and then run `cargo check` again. This way, you'll be able to see the error message again. 54 | 55 | 6. You can see the documentation of every crate that your program/package depends on. 56 | 57 | `cargo doc --open` 58 | 59 | 7. Create a library package. 60 | 61 | `cargo new --lib ` 62 | 63 | _This command will create a package with a test._ 64 | 65 | 8. Work on someone else's project: 66 | 67 | ```bash 68 | git clone url/project 69 | cd project 70 | cargo build 71 | ``` 72 | 73 | ## Memory Leaks 74 | 75 | 1. Use [Valgrind](https://www.valgrind.org/info/) to check for memory errors. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn Rust 2 | 3 | I'm learning Rust, and here are my study notes. 4 | 5 | In each program, you'll find extensive explanations. 6 | 7 | This will be a long journey. So I suggest you watching this repository for updates. 8 | 9 | ## Official Rust Book Studies Index 10 | 11 | 1. Getting Started 12 | 1. [Install Rust](notes/install.md) 13 | 2. [First Program](rpl/_01_hello/main.rs) 14 | 3. [First Cargo Program](rpl/_02_hello_cargo) 15 | 4. [Let's build a Guessing Game](rpl/_03_guessing_game) 16 | 2. Basics 17 | 1. [Ifs and Loops](rpl/_04_basics/branches/src/main.rs) 18 | 2. [Basic Types](rpl/_04_basics/types/src/main.rs) 19 | 3. [Variables](rpl/_04_basics/variables/src/main.rs) 20 | 3. Ownership & Borrowing 21 | 1. [Scopes](rpl/_05_ownership/_01_scope/src/main.rs) 22 | 2. [String Ownership](rpl/_05_ownership/_02_string/src/main.rs) 23 | 3. [Moving](rpl/_05_ownership/_03_move/src/main.rs) 24 | 4. [Funcs](rpl/_05_ownership/_04_funcs/src/main.rs) 25 | 5. [References](rpl/_05_ownership/_05_references/src/main.rs) 26 | 6. [Dangling-Pointer-Free](rpl/_05_ownership/_06_dangling/src/main.rs) 27 | 7. [Slice Internals](rpl/_05_ownership/_07_slices/src/main.rs) 28 | 4. Organizing Data 29 | 1. [Struct Basics](rpl/_06_structs/src/main.rs) 30 | 2. [Struct Example](rpl/_06_structs_example/src/main.rs) 31 | 3. [Methods: OOP Rust](rpl/_07_methods/src/main.rs) 32 | 4. [Enums: Another way to organize data](rpl/_08_enums/src/main.rs) 33 | 5. [Match Expressions](rpl/_09_match/src/main.rs) 34 | 6. [Packages](rpl/_10_packages/src/lib.rs) 35 | 7. Collections 36 | 1. [Vectors](rpl/_11_collections/src/vectors.rs) 37 | 2. [Strings](rpl/_11_collections/src/strings.rs) 38 | 3. [HashMaps](rpl/_11_collections/src/hashmaps.rs) 39 | 4. [🏋️‍♂️ Exercises 🏋️‍♀️](rpl/_11_collections/exercises/README.md) 40 | 41 | ## My Notes 42 | 43 | * 🤪 [Weird Things about Rust](notes/shocks.md) 44 | * 🤓 [Some Rust Mechanics Explained](notes/mechanics.md) 45 | * 🤩 [Some Rust Tips](notes/tips.md) 46 | * 🧐 [Rust Glossary](notes/glossary.md) 47 | * 🥶 [Useless Knowledge](notes/useless.md) 48 | * 😌 [Comparison of Rust to Other Langs](notes/langs.png) 49 | * 😐 [FAQ](notes/faq.md) 50 | * 😍 [Awesome Rust Resources](notes/resources.md) -------------------------------------------------------------------------------- /rpl/_11_collections/exercises/exercise_2_solution/src/main.rs: -------------------------------------------------------------------------------- 1 | // Convert strings to pig latin (_Keep in mind the details about UTF-8 encoding!_). 2 | fn main() { 3 | println!("{:10} -> {}", "apple", pigify("apple")); 4 | println!("{:10} -> {}", "first", pigify("first")); 5 | 6 | // let's pigify for multiple words 7 | let s = "first consonant of each word is moved to the end of the word"; 8 | 9 | // create a string with `s.len() * 2` capacity to prevent 10 | // memory fragmentation while adding new substrings. 11 | let mut ns = String::with_capacity(s.len() * 2); 12 | 13 | // split s to words, pigify, and add each one to `ns`. 14 | let mut words = s.split_whitespace(); 15 | while let Some(w) = words.next() { 16 | ns.push_str(pigify(w).as_str()); 17 | ns.push(' '); 18 | } 19 | println!("\n{}\n{}", s, ns); 20 | } 21 | 22 | // let's first make it work for a single word. 23 | // 24 | // pigify returns an owned String because 25 | // it doesn't have to retain ownership 26 | // to the returned String. 27 | fn pigify(w: &str) -> String { 28 | // get an utf-8 character iterator 29 | let mut chars = w.chars(); 30 | 31 | // get the first utf-8 char, and move the iterator to the next char. 32 | let first: char = match chars.next() { 33 | Some(c) => c, // if `w` isn't empty, `first` is `c` 34 | None => return "".to_string(), // otherwise, return "" from pigify() 35 | }; 36 | // we use match here because `next()` returns an Option. 37 | 38 | // transform the word 39 | match first { 40 | // if the word starts with a vowel: 41 | // 42 | // "apple" becomes "apple-hay" 43 | // 44 | 'a' | 'e' | 'i' | 'o' | 'u' => format!("{}-hay", w), 45 | // otherwise: 46 | // 47 | // "first" becomes "irst-fay" 48 | // 49 | // -> chars points to the 2nd char and forward. 50 | // because we moved it near the start of pigify(). 51 | // 52 | // -> as_str() returns a &str (a string slice) for that portion. 53 | // 54 | _ => format!("{}-{}ay", chars.as_str(), first), 55 | // 56 | // requirement was handling utf-8 properly. 57 | // so you shouldn't do something like this: &w[1..] 58 | // -> why? the first character could be multiple-bytes. 59 | // 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_04_funcs/src/main.rs: -------------------------------------------------------------------------------- 1 | // Passing a value to a func is similar to assigning it to a variable. 2 | // It will either MOVE or COPY the value. 3 | fn main() { 4 | let mut s = String::from("hi"); 5 | 6 | change_owner(s); // s's value (its pointer) moves 7 | // into the change_owner() 8 | // 9 | // s becomes invalid 10 | // -> rust has reclaimed its memory in 11 | // the change_owner() 12 | let n = 5; 13 | copy(n); // rust copies n (nothing moves) 14 | println!("{}", n); // -> so we can still use it 15 | 16 | // println!("{}", s); // but we can't use s 17 | // -> it was moved to the change_owner() 18 | 19 | s = give_owner(); // -> s owns give_owner's s's value now 20 | // -> s is valid now 21 | let s2 = String::from("hello"); 22 | let s3 = change_and_give_owner(s2); // -> s2 looses ownership to the func 23 | // -> and the func gives it back to s3 24 | 25 | // s2 is no longer valid: 26 | // println!("s: {} s2: {} s3: {}", s, s2, s3); 27 | println!("s: {} s3: {}", s, s3); 28 | 29 | } // out of scope: s and s3 are dropped. 30 | 31 | fn change_owner(s: String) { // main's s's new owner is this func 32 | println!("{}", s); 33 | } // out of scope: s is dropped 34 | // rust reclaims its memory 35 | 36 | fn copy(i: i32) { // receives a copy of n as i 37 | println!("{}", i); 38 | } 39 | 40 | fn give_owner() -> String { 41 | let s = String::from("hey"); // s is the owner of String("hey") 42 | 43 | s // give_owner loses the ownership to 44 | // the calling func. 45 | // -> s's value will live in the calling func. 46 | } 47 | 48 | 49 | fn change_and_give_owner(s: String) -> String { // becomes the owner of s 50 | s // loses the ownership of s to 51 | // the calling func. 52 | } -------------------------------------------------------------------------------- /rpl/_07_methods/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Rectangle { 3 | width: u32, 4 | height: u32, 5 | } 6 | 7 | // Methods are used for organization and readability purposes. 8 | // 9 | // You can declare methods with Implementations blocks like the one below. 10 | // 11 | // Rust wants you to put everything related to an instance of a type into 12 | // a single `impl` block like this. So that, no one would've to search for 13 | // the stuff they contain. 14 | impl Rectangle { 15 | // add the area method to the Rectangle. 16 | // this method accepts a ref to a Rectangle instance. 17 | fn area(&self) -> u32 { 18 | self.width * self.height 19 | } 20 | 21 | // this method also accepts another Rectangle ref. 22 | fn can_hold(&self, other: &Rectangle) -> bool { 23 | self.width > other.width && self.height > other.height 24 | } 25 | 26 | // ASSOCIATED FUNCS (AKA STATIC METHODS) 27 | // An associated func belongs to its type, instead of one of its instances. 28 | fn square(size: u32) -> Rectangle { 29 | Rectangle { 30 | width: size, 31 | height: size, 32 | } 33 | } 34 | } 35 | 36 | fn main() { 37 | let r1 = Rectangle { 38 | width: 30, 39 | height: 50, 40 | }; 41 | let r2 = Rectangle { 42 | width: 10, 43 | height: 40, 44 | }; 45 | let r3 = Rectangle { 46 | width: 60, 47 | height: 45, 48 | }; 49 | 50 | println!("r1 => {:?}", r1); 51 | println!("r2 => {:?}", r2); 52 | println!("r3 => {:?}", r3); 53 | println!( 54 | "The area of r1 is {} pixels.", 55 | r1.area(), // calls the area method by sending &r1 to 56 | // the area method as the first argument., 57 | ); 58 | println!("Can r1 hold r2? {}", r1.can_hold(&r2)); 59 | println!("Can r1 hold r3? {}", r1.can_hold(&r3)); 60 | 61 | // Automatic Referencing: 62 | // (&r1).area(); 63 | // Above is equal to: 64 | // r1.area(); 65 | // Rust can also detect whether the instance variable is mutable or not: 66 | // (&mut r1).area(); 67 | 68 | // ------------------------------------------------------------------------ 69 | 70 | // ASSOCIATED FUNCS 71 | // 72 | // -> :: is the namespace syntax. 73 | // -> An associated func is namespaced within a type. 74 | // -> Here the square fn is namespaced within the Rectangle type. 75 | 76 | let sq = Rectangle::square(10); 77 | println!("sq => {:?}, area => {}", sq, sq.area()); 78 | } 79 | -------------------------------------------------------------------------------- /notes/rustbook.md: -------------------------------------------------------------------------------- 1 | # Rust Book 2 | 3 | ## What could be better? 4 | 5 | **Tell me the notable features of Rust earlier!** 6 | 7 | * Spends too much time telling about the basics (_chapter 1-6_). However, I believe the real audience of Rust is not novices, but veterens. 8 | 9 | * Also, the book spends a lot of time explaining the module, crate, package structure (_chapter 7_) way before they are really needed. I don't care about the facade (re-exporting). 10 | 11 | * I remember wondering about what are traits from the beginning. 12 | 13 | ## The most useful chapters were these ones: 14 | * Programming a Guessing Game 15 | * Understanding Ownership 16 | 17 | ## What should have included from the start? 18 | * A tour of stdlib: io, env, net, idk?! 19 | * Rust editions could be clarified. IDK what are they. 20 | 21 | --- 22 | 23 | ## Chapter 1: Getting Started 24 | 25 | * `rustup` installation OK. 26 | * Don't talk about `rustc`, just tell me `cargo [new|run]`. 27 | * Unnecessarily talking about `Cargo.toml`. Tell me you're going to explain me later on in the Guessing game chapter. 28 | 29 | ## Chapter 2: Programming a Guessing Game 30 | 31 | * Awesome chapter, nothing to say. 32 | 33 | ## Chapter 3: Common Programming Concepts 34 | 35 | * The worst chapter ever. 36 | * Explains the basic concepts very DRY. As if it's a spec of the language... 37 | 38 | ## Chapter 4: Understanding Ownership 39 | 40 | * Awesome chapter. 41 | * Talks about stack/heap difference way earlier. Not needed at this stage. Talk about it when talking about copying integers (_where there is no need clone them_) etc. 42 | * Why explain slices here? Explain where it is needed, later on. 43 | 44 | ## Chapter 5: Structs 45 | 46 | * Another boring chapter. Dry like the 2nd one. 47 | * Methods and the Rectangle example at the end were enough. 48 | 49 | ## Chapter 6: Enums and Pattern Matching 50 | 51 | * Dry... Boring... Although there are interesting features like `match`, data binding to `enum`s, etc. These aspects should have been highlighted more. 52 | 53 | ## Chapter 7: Managing Growing Projects with Packages, ... 54 | 55 | * WTF?! Why is this here? I didn't create a big project yet. Why should I want to manage my "growing" project? Not yet. Explain me later on. 56 | 57 | * Why do you talk about the glob operator if it's often used when testing! 58 | 59 | ## Chapter 8: Common Collections 60 | 61 | * "deref coercion": Too much unnecessary complexity at this point (which is a topic of Chapter 15!). So, just show me what can be done and not without explaining the inner details yet. I can look them up if I need to. 62 | 63 | -------------------------------------------------------------------------------- /rpl/_04_basics/types/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // err: parse cannot know the type of `guess`. 3 | // let guess = "42".parse().expect("Not a number!"); 4 | 5 | // here, we tell rust that guess is an u32 variable. 6 | let guess: u32 = "42".parse().expect("Not a number!"); 7 | println!("{}", guess); 8 | 9 | // ==================================================== 10 | // SCALAR TYPES 11 | // Represent a single value. 12 | // ==================================================== 13 | 14 | // INTEGERS: 15 | // i8 to i128 and u8 to u128 16 | // -> i means signed integer 17 | // -> u means unsigned integer 18 | 19 | // there are also: 20 | // isize and usize. 21 | // 22 | // rust determines their sizes depending on the 23 | // computer the compiler runs 24 | // 25 | // for example: 26 | // on a 64-bit computer: isize is i64 and usize is u64. 27 | // on a 32-bit computer: isize is i32 and usize is u32. 28 | 29 | // INTEGER LITERALS: 30 | let _ = 1_2_3; // decimal 31 | let _: i64 = 0xdeadbeef; // hex 32 | let _ = 0o444; // octal 33 | let _ = 0b0101_1010; // binary 34 | let _ = b'I'; // byte 35 | 36 | // run with: cargo r -q --release 37 | // to see the wrapping behavior. 38 | // 39 | // 255 + 1 becomes 0. 40 | // 1111_1111 + 1 = 0000_0000 41 | 42 | // let mut over: u8 = 255; 43 | // over += 1; 44 | // println!("over: {}", over); 45 | 46 | let _ = 2.0; // f64 47 | let _: f32 = 3.0; // f32 48 | let _ = true || false; // bool 49 | let _ = '💯'; // char 50 | 51 | // TUPLES 52 | let point = (10, 20.5); 53 | let (x, y) = point; 54 | println!("x: {}, y: {}", x, y); 55 | println!("x: {}, y: {}", point.0, point.1); 56 | 57 | // ARRAYS 58 | let days = ["Monday", "Tuesday", "Wednesday", "Thursday", 59 | "Friday", "Saturday", "Sunday"]; 60 | println!("days: {}", days.join(", ")); 61 | 62 | // each element's type is i64 63 | // and there are 5 elements. 64 | let _: [i64; 5] = [1, 2, 3, 4, 5]; 65 | 66 | // 3 elements, each one is 1: [1, 1, 1] 67 | let _ = [1; 3]; 68 | 69 | hello(); 70 | say(10, 20); 71 | 72 | // {...} is an expression. 73 | let (x, y) = { 74 | let x = 1; 75 | (x + 1, 5) // <- here it returns a tuple: (2, 5) 76 | }; 77 | say(x, y); 78 | say(one().0, one().1); 79 | } 80 | 81 | fn hello() { 82 | println!("hello!"); 83 | } 84 | 85 | fn say(n: i32, m: i64) { 86 | println!("n: {}, m: {}", n, m); 87 | } 88 | 89 | fn one() -> (i32, i64) { 90 | (1, 2) 91 | } -------------------------------------------------------------------------------- /rpl/_08_enums/src/main.rs: -------------------------------------------------------------------------------- 1 | // An IP address can either be a version four or six, but not both. 2 | // 3 | // -> However, both versions are still fundamentally IP addresses. 4 | // -> They should be treated as the same type. 5 | // 6 | // So, an IP address is a good candidate to be represented as an enum: 7 | // 8 | // enum IpAddrKind { 9 | // V4, 10 | // V6, 11 | // } 12 | // 13 | // Usage: 14 | // 15 | // V4 are V6 "variants" are "namespaced" (::) within the IpAddrKind enum. 16 | // 17 | // let four = IpAddrKind::V4; 18 | // let six = IpAddrKind::V6; 19 | // 20 | // You can put it in a struct: 21 | // 22 | // struct IpAddr { 23 | // kind: IpAddrKind, // <- 24 | // address: String, 25 | // } 26 | // 27 | // Usage: 28 | // 29 | // let home = IpAddr { 30 | // kind: IpAddrKind::V4, 31 | // address: String::from("127.0.0.1"), 32 | // }; 33 | // 34 | // let loopback = IpAddr { 35 | // kind: IpAddrKind::V6, 36 | // address: String::from("::1"), 37 | // }; 38 | // 39 | // However, there is a better way. 40 | // -> Instead of using a struct, 41 | // -> You can associate values with each variant of an enum. 42 | enum IpAddr { 43 | // Enum variants can have associated values. 44 | V4(u8, u8, u8, u8), // -> represents an IPv4 address. 45 | V6(String), // -> represents an IPv6 address. 46 | } 47 | 48 | // Each variant of the Message can store something else. 49 | enum Message { 50 | Quit, // doesn't include anything 51 | Move { x: i32, y: i32 }, // includes an anonymous struct 52 | Write(String), // includes a String 53 | ChangeColor(i32, i32, i32), // includes three i32 values 54 | } 55 | // Then you can easily use it with a fn like this: 56 | // 57 | // fn processMessage(m: Message) {} 58 | // 59 | // But if we were to use a struct for each variant instead, 60 | // then we wouldn't be able to define a single type to hold 61 | // these all, and use with a fn easily. 62 | // 63 | // struct QuitMessage; 64 | // struct MoveMessage { 65 | // x: i32, 66 | // y: i32, 67 | // } 68 | // struct WriteMessage(String); 69 | // struct ChangeColorMessage(i32, i32, i32); 70 | // 71 | // fn processQuitMessage(m: QuitMessage) {} 72 | // fn processMoveMessage(m: MoveMessage) {} 73 | // fn processWriteMessage(m: WriteMessage) {} 74 | // fn processChangeColorMessage(m: ChangeColorMessage) {} 75 | // 76 | 77 | // You can also define methods on enums: 78 | impl Message { 79 | fn process(&self) { 80 | // ... 81 | } 82 | } 83 | 84 | fn main() { 85 | // declaring enums with associated values. 86 | let _home = IpAddr::V4(127, 0, 0, 1); // has an [4]u8 tuple 87 | let _loopback = IpAddr::V6(String::from("::1")); // has a String 88 | 89 | // declaring and calling a method. 90 | let m = Message::Write(String::from("hi")); 91 | m.process(); 92 | } 93 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_05_references/src/main.rs: -------------------------------------------------------------------------------- 1 | // 2 | // WHAT IS A REFERENCE? 3 | // 4 | // It's a value that refers to another value 5 | // without taking its ownership. 6 | // 7 | // Represented with a leading ampersand &. 8 | // 9 | // &s let s = String::from("hi") "hi" 10 | // 11 | // name | value name | value index | value 12 | // ---- + ------ ---- + ------ ----- + ----- 13 | // ptr | 0x5 -------> ptr | 0x01 -------> 0 | h 14 | // len | 2 1 | i 15 | // cap | 2 ----- + ----- 16 | // -----+------- 17 | // 18 | fn main() { 19 | let s = String::from("hi"); 20 | 21 | let l = strlen(&s); // strlen BORROWS s. 22 | // strlen doesn't own it. 23 | // main is the OWNER. 24 | // strlen is the BORROWER. 25 | 26 | println!("len({}) = {}", s, l); // that's why we can still use s here. 27 | 28 | // 29 | 30 | let mut cs = s; // cs is the owner of s now. 31 | 32 | change(&mut cs); // send a mutable ref of cs with change() 33 | // -> so change() can change it. 34 | 35 | println!("{}", cs); // we can still use cs because 36 | // we're the owner of it. 37 | println!("{:?}", cs); 38 | 39 | // ======================================================================== 40 | // MULTIPLE MUTABLE REFERENCES 41 | // 42 | // let mut s = String::from("hey"); 43 | // 44 | // IN THE SAME SCOPE: 45 | // 46 | // -> There can be only a single mutable borrower (reference). 47 | // { 48 | // let mutRefToS = &mut s; 49 | // 50 | // } 51 | // mutRefToS goes out of scope, Rust drops it. 52 | // That's why you can make a new reference to it here. 53 | // 54 | // let mutRef2ToS = &mut s; 55 | // 56 | // -> There can be multiple non-mutable borrowers. 57 | // let rs1 = &s; // immutable borrower 58 | // let rs2 = &s; // immutable borrower 59 | // 60 | // -> There can't be a mutable borrower if there are immutable borrowers. 61 | // let rs3 = &mut s; // mutable borrower 62 | // println!("{} {} {}", rs1, rs2, rs3); 63 | // 64 | // ======================================================================== 65 | 66 | } // the main is the owner of s, and cs. 67 | // they go out of scope and but Rust drops them. 68 | 69 | fn strlen(s: &String) -> usize { // s is a reference to a String 70 | s.len() 71 | } // s goes out of scope but nothing happens. 72 | // because strlen isn't the owner of s, 73 | // the main() is. 74 | 75 | /* 76 | this won't work. 77 | s is not a mutable reference. 78 | 79 | fn change(s: &String) { 80 | s.push_str(" there!"); 81 | } 82 | */ 83 | fn change(s: &mut String) { 84 | s.push_str(" there!"); 85 | } -------------------------------------------------------------------------------- /notes/resources.md: -------------------------------------------------------------------------------- 1 | # Resources 2 | 3 | ## Getting Started 4 | 5 | * [Intorust Screencasts](http://intorust.com/) 6 | * [Tour of Rust](https://tourofrust.com/) 7 | * [Learning Rust](https://learning-rust.github.io/) 8 | * [A Half-Hour to Learn Rust](https://fasterthanli.me/blog/2020/a-half-hour-to-learn-rust/) 9 | * [Let's build a Guessing Game](https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html) 10 | * [Read Rust: Getting Started](https://readrust.net/getting-started) 11 | * [Rust 101](https://www.ralfj.de/projects/rust-101/main.html) 12 | * [Exercism Rust Track](https://exercism.io/tracks/rust) 13 | * [Web Dev with Rocket](https://christine.website/blog/how-i-start-rust-2020-03-15) 14 | 15 | ## Getting Help 16 | 17 | * [The #beginners channel on Discord](https://discord.gg/rust-lang) 18 | * [Users forum](https://users.rust-lang.org/) 19 | * **IRC:** 20 | * [#rust](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust) 21 | * [#rust-gamedev](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-gamedev) 22 | * [#rust-osdev](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-osdev) 23 | * [#rust-webdev](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-webdev) 24 | 25 | ## Resources 26 | 27 | * [Learning Resources](https://github.com/ctjhoa/rust-learning) 28 | * [Official Learning Resources](https://www.rust-lang.org/learn) 29 | * [Official Rust Book](https://doc.rust-lang.org/book) 30 | * [Read Rust](https://readrust.net/) 31 | * [Rust Cookbook](https://rust-lang-nursery.github.io/rust-cookbook/) 32 | * [Awesome Rust](https://github.com/rust-unofficial/awesome-rust) 33 | * [Rust Style Guidelines](https://doc.rust-lang.org/1.0.0/style/README.html) 34 | * [Rust by Example](https://doc.rust-lang.org/stable/rust-by-example/) 35 | * [Code Explainer](https://jrvidal.github.io/explaine.rs/) 36 | * [This Week in Rust](https://this-week-in-rust.org/) 37 | 38 | ## Bloggers 39 | 40 | * [Niko Matsakis::Baby Steps](http://smallcultfollowing.com/babysteps/) 41 | * [Mara's Blog](https://blog.m-ou.se/) 42 | * [llogiq](https://llogiq.github.io/) 43 | * [Christine Dodrill](https://christine.website/blog) 44 | * [Barely Functional](https://blog.mgattozzi.dev/) 45 | * [In Pursuit of Lazziness](https://manishearth.github.io/) 46 | * [seanmonstar](https://seanmonstar.com/) 47 | * [Stjepan's blog](https://stjepang.github.io/) 48 | 49 | ## Articles 50 | 51 | * [References in Rust](https://blog.thoughtram.io/references-in-rust/) 52 | * [Why Rust?](https://christine.website/blog/why-rust-2020-02-15) 53 | * [Rust's runtime](https://blog.mgattozzi.dev/rusts-runtime/) 54 | * [What's a lang item?](https://manishearth.github.io/blog/2017/01/11/rust-tidbits-what-is-a-lang-item/) 55 | * [Writing Python inside your Rust code](https://blog.m-ou.se/writing-python-inside-rust-1/) 56 | * [Rust Disassembly](https://giordi91.github.io/post/disassemlbyrust1/) 57 | * [Porting Godot Games to Rust](https://paytonrules.com/post/games-in-rust-with-godot-part-one/) 58 | * [Why Rust?](http://rust-class.org/0/pages/using-rust-for-an-undergraduate-os-course.html) 59 | * [How to read Rust docs?](http://blog.frqc.info/post/how-to-read-rust-docs/) 60 | * [What's Rust's turbofish?](https://techblog.tonsser.com/posts/what-is-rusts-turbofish) -------------------------------------------------------------------------------- /rpl/_06_structs/src/main.rs: -------------------------------------------------------------------------------- 1 | // You can use a struct type (also an enum type) represent a concept, and organize similar data under a single umbrella. 2 | 3 | // User is a struct type 4 | struct User { 5 | username: String, 6 | email: String, 7 | sign_in_count: u64, 8 | active: bool, 9 | } 10 | 11 | fn main() { 12 | // root is an instance of the User struct. 13 | // 14 | // to change the root instance, its entire instance 15 | // should be declared as mutable. 16 | let mut root = User { 17 | username: String::from("guest"), 18 | email: String::from("root@universe.com"), 19 | sign_in_count: 5, 20 | active: false, 21 | }; 22 | 23 | // change the username field 24 | root.username = String::from("root"); 25 | 26 | println!("{}'s email: {}", root.username, root.email); 27 | // ---------------------------------------------------------- 28 | 29 | let guest = build_user(String::from("guest"), String::from("guest@srv.com")); 30 | let active = if guest.active { "active" } else { "not active" }; 31 | println!("{}'s email: {}", guest.username, guest.email); 32 | println!("\t{} and signed on {} times.", active, guest.sign_in_count); 33 | // ---------------------------------------------------------- 34 | let jack = User { 35 | username: String::from("jack"), 36 | email: String::from("jack@secret.org"), 37 | // CUMBERSOME: 38 | // active: root.active, 39 | // sign_in_count: root.sign_in_count, 40 | // 41 | // STRUCT UPDATE SYNTAX: 42 | ..root 43 | }; 44 | let active = if guest.active { "active" } else { "not active" }; 45 | println!("{}'s email: {}", jack.username, jack.email); 46 | println!("\t{} and signed on {} times.", active, jack.sign_in_count); 47 | 48 | // ---------------------------------------------------------- 49 | // TUPLE STRUCTS 50 | 51 | // Example: struct Point(i32, i32); 52 | // -> Have a type name: Point. 53 | // -> Have fields : (i32, i32). 54 | // -> Fields don't have names. 55 | // 56 | // When to use? 57 | // -> To give the tuple a name to make it different from other types. 58 | // -> When naming every other field a name is verbose and reduntant. 59 | 60 | struct Color(i32, i32, i32); // (Red, Green, Blue) 61 | struct Point(i32, i32, i32); // (X, Y, Z) 62 | 63 | let mut _black = Color(0, 0, 0); 64 | let mut _origin = Point(0, 0, 0); 65 | 66 | // Each struct you define is its own type, 67 | // even though the fields within the struct 68 | // have the same types. 69 | // 70 | // _black = _origin // MISMATCHED TYPES: 71 | // _black is a Color 72 | // _origin is a Point 73 | 74 | // You can access tuple struct fields using their indexes. 75 | println!("R: {}, G: {}, B: {}", _black.0, _black.1, _black.2); 76 | } 77 | 78 | fn build_user(email: String, username: String) -> User { 79 | User { 80 | // CUMBERSOME: 81 | // email: email, 82 | // username: username, 83 | // 84 | // FIELD-INIT SHORTHAND: 85 | email, 86 | username, 87 | 88 | sign_in_count: 1, 89 | active: true, 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /rpl/_11_collections/exercises/exercise_1_solution/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // Given a list of integers: 1..10 3 | 4 | // 1 -> use a vector 5 | let mut ints = vec![10, 8, 7, 3, 4, 7, 7, 2]; 6 | 7 | // 2 -> return mean (the average value) 8 | println!("mean: {}", mean(&ints)); 9 | 10 | // ints is mutable so we can sort it. 11 | ints.sort(); 12 | 13 | // 3 -> return median (when sorted, the value in the middle position) 14 | println!("median: {}", median(&ints)); 15 | 16 | // 4 -> return mode (the value that occurs most often) 17 | println!("mode: {:?}", mode(&ints)); 18 | } 19 | 20 | // accept a slice &[i32] instead of a vector Vec 21 | // this way sum() can accept a vector as well as a slice, etc. 22 | fn sum(nums: &[i32]) -> i32 { 23 | let mut t = 0; 24 | for n in nums { 25 | t += *n; 26 | } 27 | t 28 | } 29 | 30 | fn mean(nums: &[i32]) -> f32 { 31 | // You can use `as T` to convert values. 32 | // For example: `as f32` means convert the value to f32. 33 | let len = nums.len() as f32; 34 | let s = sum(nums) as f32; 35 | s / len 36 | 37 | // ALTERNATIVE SOLUTION: 38 | // Rust is a functional language. 39 | // You can use Lazy iterators to sum values, and more. 40 | /* 41 | nums 42 | // returns an iterator from the nums slice. 43 | .iter() 44 | // -> sum all the numbers. 45 | // -> :: is the turbo-fish syntax. 46 | // tells `sum()` that it's going to sum 47 | // i32 values. 48 | .sum::() as f32 49 | / 50 | nums.len() as f32 51 | */ 52 | } 53 | 54 | fn median(nums: &[i32]) -> f32 { 55 | // match an arm depending on the length of the numbers in the nums 56 | match nums.len() { 57 | 0 => 0.0, // return 0.0 if l is zero? 58 | 1 => nums[0] as f32, // return the first element if l is one? 59 | 60 | // first, put nums.len() into l. 61 | // then check, is l divisible by 2? 62 | // if so return the average of middle two elements 63 | l if l % 2 == 0 => mean(&vec![nums[l / 2 - 1], nums[l / 2]]), 64 | 65 | l => nums[l / 2] as f32, // if l is odd, return the middle element. 66 | } 67 | } 68 | 69 | use std::collections::HashMap; 70 | 71 | fn mode(nums: &[i32]) -> i32 { 72 | // multi-variable assignment? nope. 73 | // see this: https://github.com/rust-lang/rfcs/issues/372 74 | let mut mo = 0; 75 | let mut max = 0; 76 | 77 | // although we can do something similar below using an iterator, 78 | // it'd be out of scope for now. because you didn't learn it yet. 79 | // so we're going to use a simple for loop. 80 | 81 | // collect frequencies in a hash map. 82 | let mut freqs = HashMap::with_capacity(nums.len()); 83 | for n in nums { 84 | // n contains a reference to the next number in the nums slice. 85 | // asterisk allows us to change the value from the same memory position. 86 | *freqs.entry(n).or_insert(0) += 1; 87 | 88 | // get the value from key `n`. 89 | // note: you can use unwrap() here because we already know that a value 90 | // with the key `n` exist from the code line above. 91 | let count = *freqs.get(n).unwrap(); 92 | 93 | // find the number with the highest frequency, so far. 94 | if count > max { 95 | max = count; 96 | mo = *n; 97 | } 98 | } 99 | mo 100 | 101 | // study this for an alternative implementations (optional): 102 | // https://rust-lang-nursery.github.io/rust-cookbook/science/mathematics/statistics.html 103 | } 104 | -------------------------------------------------------------------------------- /rpl/_09_match/src/main.rs: -------------------------------------------------------------------------------- 1 | enum UsState { 2 | Alabama, 3 | Alaska, 4 | // ... 5 | } 6 | 7 | // each Coin variant holds a u64 value. 8 | enum Coin { 9 | Penny(u64), 10 | Nickel(u64), 11 | Dime(u64), 12 | 13 | // this one also holds two values: a u64, and a UsState. 14 | Quarter(u64, UsState), 15 | } 16 | 17 | fn main() { 18 | println!("10 pennys is {} cent(s).", Coin::Penny(10).cents()); 19 | println!("10 nickels is {} cent(s).", Coin::Nickel(10).cents()); 20 | println!("10 dimes is {} cent(s).", Coin::Dime(10).cents()); 21 | println!( 22 | "10 Alabama Quarters is {} cent(s).", 23 | Coin::Quarter(10, UsState::Alabama).cents() 24 | ); 25 | println!( 26 | "10 Alaska Quarters is {} cent(s).", 27 | Coin::Quarter(10, UsState::Alaska).cents() 28 | ); 29 | 30 | // ---------------------------------------------------------------------- 31 | // match is exhaustive. 32 | // -> this means that you need to exercise all the variants of a value. 33 | let n = 3u8; 34 | match n { 35 | 0 => println!("zero"), 36 | 1 => println!("one"), 37 | 3 => println!("three"), 38 | 5 => println!("five"), 39 | 7 => println!("seven"), 40 | // however, _ will match any value. 41 | // so you can exhaust a match this way. 42 | // uncomment this and see what happens. 43 | _ => (), // () is the unit value, literally empty. 44 | } 45 | 46 | // ---------------------------------------------------------------------- 47 | // In Rust, there isn't a `null` value. 48 | // 49 | // However, there is an Option enum which can either be: 50 | // 51 | // Some 52 | // None 53 | // 54 | // Some: Option value stores data. 55 | // None: Option value stores nothing. 56 | // 57 | // This way, Rust prevents the Billion-Dollar Null value mistake. 58 | // 59 | // You always need to use match to look inside the option value, 60 | // and find out if it has a value inside (Some), or nothing (None). 61 | // 62 | 63 | let mut n = Some(6); 64 | match n { 65 | Some(6) => println!("six"), 66 | _ => (), 67 | } 68 | 69 | // However, this can be cumbersome. 70 | // Especially, if you only want to print if `n` is 6, as above. 71 | // 72 | // There is a better way: 73 | if let Some(6) = n { 74 | println!("six"); 75 | } 76 | // `if let` is syntactic sugar for a match that runs code when the value 77 | // matches one pattern and then ignores all other values. 78 | 79 | // using an else clause to match other values than 6 is also possible. 80 | n = Some(7); 81 | if let Some(6) = n { 82 | println!("six"); 83 | } else { 84 | println!("not six, it's {}.", n.unwrap_or_default()); 85 | } 86 | } 87 | 88 | impl Coin { 89 | // this method can be used from an instance of the Coin enum. 90 | fn cents(&self) -> u64 { 91 | // match an arm depending on the variant of the Coin enum: 92 | // Penny, Nickel, Dime, and Quarter. 93 | // `amount` is being populated from a variant's data. 94 | match self { 95 | Coin::Penny(amount) => amount * 1, // this arm returns 1 96 | Coin::Nickel(amount) => amount * 5, // this arm returns 5 97 | Coin::Dime(amount) => amount * 10, // this arm returns 10 98 | 99 | Coin::Quarter(amount, state) => { 100 | let c = match state { 101 | UsState::Alabama => 15, // this arm returns 15 102 | UsState::Alaska => 25, // this arm return 10 103 | }; 104 | amount * c 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /rpl/_03_guessing_game/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "cfg-if" 5 | version = "0.1.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "getrandom" 10 | version = "0.1.14" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | dependencies = [ 13 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 14 | "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", 15 | "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", 16 | ] 17 | 18 | [[package]] 19 | name = "guessing_game" 20 | version = "0.1.0" 21 | dependencies = [ 22 | "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 23 | ] 24 | 25 | [[package]] 26 | name = "libc" 27 | version = "0.2.71" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | 30 | [[package]] 31 | name = "ppv-lite86" 32 | version = "0.2.8" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | 35 | [[package]] 36 | name = "rand" 37 | version = "0.7.3" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | dependencies = [ 40 | "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", 42 | "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 45 | ] 46 | 47 | [[package]] 48 | name = "rand_chacha" 49 | version = "0.2.2" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | dependencies = [ 52 | "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 53 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 54 | ] 55 | 56 | [[package]] 57 | name = "rand_core" 58 | version = "0.5.1" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | dependencies = [ 61 | "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", 62 | ] 63 | 64 | [[package]] 65 | name = "rand_hc" 66 | version = "0.2.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | dependencies = [ 69 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 70 | ] 71 | 72 | [[package]] 73 | name = "wasi" 74 | version = "0.9.0+wasi-snapshot-preview1" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | 77 | [metadata] 78 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 79 | "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" 80 | "checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" 81 | "checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" 82 | "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 83 | "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 84 | "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 85 | "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 86 | "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 87 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_03_move/src/main.rs: -------------------------------------------------------------------------------- 1 | // Variables have two type of semantics: 2 | // 3 | // 1. Move Semantics: 4 | // 5 | // -> Variable's value moves to another variable 6 | // without copying. 7 | // 8 | // -> Used for heap-allocated values like a String. 9 | // 10 | // 11 | // 2. Copy Semantics: 12 | // 13 | // -> Rust copies the variable's value, and uses 14 | // the new value for the new variable. 15 | // 16 | // -> Used for scalar values like integers. 17 | // 18 | // -> This kind of values usually live on stack. 19 | // 20 | // SEE: https://doc.rust-lang.org/std/marker/trait.Copy.html 21 | fn main() { 22 | // ======================================= 23 | // STACK MEMORY 24 | // ======================================= 25 | 26 | // -> 5 can be allocated on the stack memory. 27 | // -> It's a simpler scalar value. 28 | // -> So Rust can copy it cheaply. 29 | let x = 5; 30 | 31 | // WHAT HAPPENS BELOW? 32 | // 33 | // 1. Rust COPIES x's value: 5. 34 | // 2. And BINDS the new value to the y variable. 35 | // 3. What the y contains is a copy. 36 | let y = x; 37 | // Here x and y have different memory locations. 38 | println!("x: {} y: {}", x, y); 39 | 40 | // ======================================= 41 | // HEAP MEMORY 42 | // ======================================= 43 | 44 | // WHAT IS A STRING? 45 | // 46 | // String::from("hi") looks like this: 47 | // 48 | // This part is usually But this part should 49 | // allocated on the stack. live on the heap. 50 | // 51 | // --------+--------- ----- + ----- 52 | // name | value index | value 53 | // --------+--------- ----- + ----- 54 | // ptr | 0x01 -------> 0 h 55 | // len | 2 1 i 56 | // cap | 2 ----- + ----- 57 | // --------+--------- ^ 58 | // | 59 | // +-------+ 60 | // | 61 | // s1 contains the String value below. | 62 | let s1 = String::from("hi"); // | 63 | // | 64 | // let s2 = s1; // | <-- READ THE CODE 65 | // | 66 | // -> s2 is a new String value. | 67 | // its ptr points to the same location | 68 | // on the heap memory. | 69 | // | 70 | // --------+--------- | 71 | // name | value | 72 | // --------+--------- | 73 | // ptr | 0x01 --------------------+ 74 | // len | 2 75 | // cap | 2 76 | // --------+--------- 77 | 78 | // 79 | // THE CODE BELOW WON'T WORK. 80 | // 81 | // println!("{} {}", s1, s2); 82 | 83 | // 84 | // WHY? 85 | // 86 | // -> Rust moves s1's value to s2. 87 | // -> s2 is the new OWNER of s1's value. 88 | // -> s1 is no longer valid. 89 | // -> goes out of scope. 90 | // -> rust claims its memory. 91 | 92 | // 93 | // WHAT WOULD WORK?? 94 | // 95 | let s2 = s1.clone(); // expensive op 96 | println!("{} {}", s1, s2); 97 | // WHY? 98 | // -> s2 has a deep-copy of s1's value. 99 | // -> there are one more "hi" on the heap now. 100 | // -> and its owner is s2. 101 | 102 | // 103 | // BUT IT WAS WORKING WITH AN INTEGER LITERAL BEFORE? 104 | // (IN THE STACK MEMORY SECTION ABOVE) 105 | // 106 | // BUT WHY? TELL ME MORE: 107 | // 108 | // 1. Simple values like an integer doesn't need to be cloned. 109 | // 2. They can be copied by Rust automatically. 110 | // 3. It has a Copy trait. 111 | // SEE: https://doc.rust-lang.org/std/marker/trait.Copy.html 112 | // 113 | } 114 | -------------------------------------------------------------------------------- /rpl/_05_ownership/_07_slices/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // ======================================================================== 3 | // ARRAYS 4 | // -> An array is a contiguous collection of objects of the same type: T. 5 | // -> The compiler knows an array's size at compile-time. 6 | // -> Arrays are stack allocated. 7 | // 8 | // You can declare an array like this: 9 | // 10 | // let nums: [i32; 3] = [1, 2, 3]; 11 | // ^ ^ ^ 12 | // | | +---------------+ 13 | // | +--------+ | 14 | // Type of elements | | 15 | // Array's length | 16 | // Array's Elements 17 | // 18 | 19 | // ======================================================================== 20 | // SLICES 21 | // -> A slice is a reference to a part of a contiguous sequence of 22 | // elements. 23 | // -> It's actually a two-word object: 24 | // -> 1st word: A pointer to the original data. 25 | // -> 2nd word: The length of the slice. 26 | // 27 | // For example: 28 | // -> A slice can borrow a portion of the array: nums. 29 | // 30 | // let borrowed_array = &nums; 31 | // ^ 32 | // | 33 | // &[i32] 34 | // an i32 slice 35 | // 36 | // 37 | 38 | // ======================================================================== 39 | // A STRING SLICE EXAMPLE 40 | // 41 | // let s = String::from("hello"); // s is a string slice 42 | 43 | // ======================================================================== 44 | // SLICING 45 | // 46 | // [starting_index..ending_index] 47 | // 48 | // &s[0..len(s)] // hello 49 | // &s[1..3] // el 50 | // &s[0..] // hello 51 | // &s[..len(s)] // hello 52 | // &s[..] // hello 53 | // 54 | 55 | let s = String::from("they were walking down the street"); 56 | let word = first_word(&s); 57 | println!("{}", word); 58 | 59 | // ======================================================================== 60 | // string literals are slices. 61 | // 62 | // we can pass them directly to an fn if it accepts 63 | // a string slice. 64 | println!("{}", first_word("hello world")); 65 | 66 | // ======================================================================== 67 | // ERROR 68 | // String slice range indices should respect UTF-8 character boundaries. 69 | // 70 | // let s = String::from("yolun aşağısına doğru yürüyorlardı"); 71 | // println!("{}", &s[6..8]); 72 | 73 | // ======================================================================== 74 | // If you could borrow immutably and mutably in the same scope, errors like 75 | // below could happen. Rust doesn't allow this to happen. 76 | // 77 | // Comment out to see the error. 78 | // 79 | // let mut s = String::from("they were walking down the street"); 80 | // let word = first_word(&s); // get a slice to the first word portion of s 81 | // 82 | // &s means an immutable borrow 83 | // 84 | // s.clear(); // err -> can't clear s because clear needs 85 | // to borrow s mutably. 86 | // 87 | // println!("{}", word); // could print a non-existent word!.. 88 | } 89 | 90 | fn first_word(s: &str) -> &str { 91 | let bytes = s.as_bytes(); 92 | 93 | for (i, &b) in bytes.iter().enumerate() { 94 | if b == b' ' { 95 | return &s[..i]; 96 | } 97 | } 98 | &s[..] 99 | } 100 | // -> As in the first_word() above, 101 | // It's better to accept a string slice 102 | // instead of a String reference. 103 | // 104 | // -> This way, first_word can accept both a String ref, 105 | // as well as a string literal, and so on. 106 | // 107 | fn _use_first_word() { 108 | let s = String::from("hey"); 109 | let _ = first_word(&s[..]); // pass the whole s 110 | 111 | let l = "hello"; // a string literal 112 | let _ = first_word(&l[..]); // pass the string literal as a slice. 113 | let _ = first_word(l); // <- or simply pass itself. 114 | // works because string literals == slices 115 | } -------------------------------------------------------------------------------- /rpl/_03_guessing_game/src/main.rs: -------------------------------------------------------------------------------- 1 | // 💯 See: _naked.rs for the annotation-free version. 2 | 3 | // We need to bring the input/output library into scope, 4 | // So we can accept user input and print the result as output. 5 | // std => Standard Library 6 | use std::io; 7 | 8 | // For the stdout().flush() below. 9 | use std::io::Write; 10 | 11 | // We want to use the Rng from the rand crate to generate 12 | // Random numbers. 13 | // 14 | // To install this, first you need to go to your Cargo.toml 15 | // file, and add it there, below the [dependencies] section. 16 | use rand::Rng; 17 | 18 | // To compare values we'd also need to use the Ordering enum. 19 | // 20 | // Ordering enum contains: Less, Equal, and Greater. 21 | // 22 | // --> ::* at the end returns every value in the Ordering. 23 | // So we can use them directly like Less, Equal, Greater. 24 | // Instead of: Ordering::Less, Ordering::Equal, etc. 25 | use std::cmp::Ordering::*; 26 | 27 | fn main() { 28 | // Let's introduce a new immutable variable named secret. 29 | // We're going to compare this one with the user input: guess. 30 | // 31 | // --> Variables are immutable by default. 32 | // (Immutable == Unchangeable). 33 | // 34 | // --> thread_rng() returns us a random generator that 35 | // will be seeded by the current operating system thread. 36 | // --> gen_range() is a method on the returned random 37 | // generator. It generates a random number between 1 and 100. 38 | let secret = rand::thread_rng().gen_range(1, 101); 39 | 40 | // loops infinitely 41 | loop { 42 | print!("guess: "); 43 | 44 | // stdout gets flushed on newlines. 45 | // print! doesn't contain a newline. 46 | // So we need to flush stdout ourselves. 47 | io::stdout().flush().expect("🤬 cannot flush"); 48 | 49 | // Let's create a new, empty, and mutable string variable. 50 | // 51 | // ==> mut makes the variable mutable. 52 | // 53 | // ==> String::new() creates and returns a new String instance. 54 | // --> The String type is a growable, UTF-8 encoded text. 55 | // --> :: indicates new is an associated fn of String. 56 | // (aka a static method). 57 | // 58 | // ==> Type Inference 59 | // --> Rust automatically guesses the type of the guess variable. 60 | // --> Since String::new() returns a String, so guess is also 61 | // a String. 62 | let mut guess = String::new(); 63 | 64 | // Let's accept user input and put it into the guess variable. 65 | // 66 | // ==> io::stdin() calls the stdin fn from the io module. 67 | // --> Returns a std::io::Stdin instance. 68 | // --> Stdin represents a handle to the stdin for your terminal. 69 | io::stdin() 70 | // Let's read the user input into guess. 71 | // 72 | // read_line takes whatever the user types into stdin, and 73 | // place that into a string, so it takes a string as an 74 | // argument. 75 | // 76 | // --> read_line() calls the read_line method on the Stdin 77 | // instance to get input from the user. 78 | // --> `&mut guess` passes the mutable variable to the 79 | // read_line method. So the readline can update it. 80 | // --> & indicates a reference. This allows read_line 81 | // to work with the same guess instance. Prevents 82 | // copying on memory. Passes a pointer to it. 83 | .read_line(&mut guess) 84 | // Let's handle the error: Could we read the user input? 85 | // 86 | // ==> read_line returns an io::Result enum that can either 87 | // be Ok, or Err. Ok, and Err are called the variants of 88 | // the io::Result enum type. 89 | // 90 | // Ok --> User input read successfuly. 91 | // Err --> Couldn't read the user input. 92 | // 93 | // ==> Here we call the expect method of the io::Result. 94 | // --> The result of the read_line defines the 95 | // behavior of the expect method. 96 | // --> If the result is Err: expect() crashes the 97 | // program, and prints the error message. 98 | // --> If the result is Ok: expect() extracts the 99 | // return value from the Ok. 100 | // 101 | // ==> If you don't use the expect, `cargo check` will 102 | // give you a warning about that you should handle 103 | // the error. 104 | .expect("🤬 cannot read input"); 105 | 106 | // Let's convert the user input into an integer. 107 | // 108 | // Rust is a strongly statically-typed programming language. 109 | // --> So you can't compare the user input (a string) 110 | // to the secret (an i32—the default 32-bit integer type). 111 | // 112 | // ==> Let me explain the code below: 113 | // --> guess below is a new guess variable with u32 type. 114 | // --> u32 == a 32-bit unsigned integer. 115 | // --> trim() removes the spaces around the previous guess 116 | // string variable's value. 117 | // --> parse() returns the string value as an u32 value. 118 | // --> expect checks if the previous guess's value was an 119 | // integer, if not, crashes the program. 120 | // 121 | // let guess: u32 = guess.trim().parse() 122 | // .expect("Please type a number!"); 123 | 124 | // Let's not crash the program, and gracefully handle the err. 125 | // == match is explained at the end of the program == 126 | let guess: u32 = match guess.trim().parse() { 127 | // 1. if the input is a number, return it. 128 | Ok(n) => n, 129 | 130 | // 2. if it's not reloop. 131 | // --> _ is a catch-all value. 132 | // Here, it catches every type of err. 133 | Err(_) => { 134 | println!("🤬 not a number"); 135 | continue; 136 | } 137 | }; 138 | 139 | // crab pincers == {} — holds a value in-place. 140 | // --> println injects values into a string using placeholders. 141 | // --> {} is a placeholder, and the value is the guess's 142 | // value. 143 | println!("you say: {}, let's see...", guess); 144 | 145 | // Let's compare the user input with the secret number. 146 | // 147 | // ==> cmp() method can compare two values that can be compared. 148 | // --> & means that cmp takes the reference of the secret variable. 149 | // --> It returns a std::cmp::Ordering value. 150 | // 151 | // ==> match expression allows you to compare values. 152 | match guess.cmp(&secret) { 153 | Less => println!("🤨 bigger"), 154 | Greater => println!("🤨 smaller"), 155 | Equal => { 156 | println!("🥳 you rock!"); 157 | break; // exit the loop 158 | } 159 | } 160 | println!(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /rpl/_11_collections/src/hashmaps.rs: -------------------------------------------------------------------------------- 1 | // 2 | // Rust's HashMap is an ordinary map type that you might already know about from other langs. 3 | // 4 | // -> They are stored on the heap memory. 5 | // 6 | // So Rust's hash map is: 7 | // 8 | // HashMap 9 | // 10 | // HashMap is a generic type: 11 | // 12 | // -> Keys are of the type `K`, and, 13 | // -> Values are of type `V`. 14 | // 15 | 16 | // first, you need to bring it to this scope. 17 | use std::collections::HashMap; 18 | 19 | #[allow(unused)] 20 | pub fn run() { 21 | // =================================================================== 22 | // let's create a new hash map. 23 | // =================================================================== 24 | let mut reviews = HashMap::new(); 25 | 26 | // =================================================================== 27 | // let's add some game reviews. 28 | // 29 | // key => game name (&str) 30 | // value => review score (floating-point number) 31 | // =================================================================== 32 | reviews.insert("Mass Effect", 7.9); 33 | reviews.insert("Sam and Max: Hit the Road", 9.5); 34 | reviews.insert("Beneath a Steel Sky", 9.0); 35 | reviews.insert("Dune", 8.0); 36 | 37 | { 38 | // or, you can construct it from these vectors. 39 | let games = vec!["Mass Effect", "Sam and Max: Hit the Road"]; 40 | let scores = vec![7.9, 9.5]; 41 | 42 | // now, all you need is to zip them together into a map. 43 | let mut reviews: HashMap<_, _> = games.into_iter().zip(scores.into_iter()).collect(); 44 | // ^ ^ | | 45 | // |_/ v v 46 | // Guesses the key and value Keys = &str Values = float 47 | // types automatically <---------====---------------===== 48 | // from the vectors 49 | 50 | // =================================================================== 51 | // ☝️ into_iter() 52 | // 53 | // Above, each `into_iter()` takes ownership of a vector. 54 | // 55 | // So you can no longer use the games, or scores. 56 | // 57 | // let _ = games.get(0).unwrap(); 58 | // let _ = scores.get(0).unwrap(); 59 | // 60 | // =================================================================== 61 | } 62 | 63 | // =================================================================== 64 | // let's access the values inside a map 65 | // =================================================================== 66 | let mass_effect = reviews.get("Mass Effect"); 67 | println!( 68 | "They rated Mass Effect with a score of {:?}.", 69 | mass_effect.unwrap() // unwrap is not cool, you'll see why below. 70 | ); 71 | 72 | // =================================================================== 73 | // let's check for the existence of keys 74 | // =================================================================== 75 | 76 | // 77 | // first, you're going to learn what happens if you try to access 78 | // a non-existing key. 79 | // 80 | let ping_pong = reviews.get("Ping Pong"); 81 | 82 | // 83 | // uncomment the following line and see what happens: 84 | // 85 | // println!( 86 | // "They rated Ping Pon with a score of {:?}", 87 | // ping_pong.unwrap() 88 | // ); 89 | // 90 | 91 | // now let's learn how to prevent panicking. 92 | if let None = ping_pong { 93 | println!("I don't know anything about the Ping Pong game."); 94 | } 95 | // ☝️ remember, `if let` is syntactic sugar for `match`. 96 | // here, we check if ping_pong is one of the variants of 97 | // the Option enum. 98 | 99 | // let's check for an existing game. 100 | let sam_and_max = "Sam and Max: Hit the Road"; 101 | if let Some(score) = reviews.get(sam_and_max) { 102 | println!( 103 | "But they also rated {} with a score of {:?}.", 104 | sam_and_max, score, 105 | ); 106 | } 107 | // ☝️ here, we check if there is "some" value in the value returned 108 | // by the `reviews.get(sam_and_max)`. 109 | // 110 | // if there is, Rust binds it to the `score` variable. 111 | 112 | // =================================================================== 113 | // let's iterate over each key/value pair 114 | // =================================================================== 115 | for (key, value) in &reviews { 116 | println!("-> They rated {} with a score of {}.", key, value); 117 | } 118 | // ☝️ remember: borrow, do not unnecessarily own. 119 | // 120 | // if you've used reviews above instead of &reviews, 121 | // then you'd be owning, not borrowing. 122 | // 123 | // so, you would no longer be able to use reviews. 124 | // it would have been dropped after the loop ends. 125 | 126 | // =================================================================== 127 | // let's overwrite a value 128 | // =================================================================== 129 | // you can overwrite a value if you re-insert with the same key again. 130 | reviews.insert("Mass Effect", 8.5); 131 | // let's pretty print everything in the map. 132 | println!("{:#?}", reviews); 133 | 134 | // =================================================================== 135 | // let's insert a value only if there isn't a key with the same name 136 | // =================================================================== 137 | reviews.entry("Ping Pong").or_insert(6.0); 138 | // adds Ping Pong with a score of 6.0 139 | 140 | reviews.entry("Ping Pong").or_insert(8.0); 141 | // has no effect, reviews has Ping Pong 142 | 143 | println!("{:#?}", reviews); 144 | 145 | // =================================================================== 146 | // let's create a program to find word frequencies in a str 147 | // =================================================================== 148 | let text = "that that exists exists in that that that that exists exists in"; 149 | 150 | let mut freqs = HashMap::new(); 151 | 152 | for w in text.split_whitespace() { 153 | // split_whitespaces() returns an iterator that returns string sub-slices 154 | // from `text`. they don't re-allocate. rust is as efficient as it goes. 155 | 156 | let c = freqs.entry(w).or_insert(0); 157 | // c -> becomes 0 if `w` key doesn't exist on the map. 158 | // entry(w) -> returns the entry of a key from the hash map. 159 | // or_insert(0) -> if the key was absent, inserts the key `w` 160 | // with a value of 0. 161 | 162 | *c += 1; 163 | // otherwise: 164 | // -> or_insert() returns the existing entry in the map 165 | // as a mutable reference (&mut i32). 166 | // -> so you need to dereference it to get the i32 value. 167 | // -> finally, we can increment it. 168 | } 169 | // since each c goes out of scope after the loop's scope, the map's 170 | // values can be used afterwards. otherwise, this wouldn't be possible. 171 | // remember, rust doesn't allow immutable & mutable borrowers co-exist. 172 | 173 | println!("{:?}", freqs); 174 | } 175 | -------------------------------------------------------------------------------- /rpl/_10_packages/src/lib.rs: -------------------------------------------------------------------------------- 1 | // 2 | // +-----------------+ 3 | // | MODULE | 4 | // | +-------------+ | 5 | // | | PACKAGE | | 6 | // | | +---------+ | | 7 | // | | | CRATE | | | 8 | // | | +---------+ | | 9 | // | +-------------+ | 10 | // +-----------------+ 11 | // 12 | 13 | // You can use modules to group related definitions together. 14 | // So others can find what they're looking for more easily. 15 | // That's why you should name your modules well. 16 | 17 | // `mod` defines a new module named: `front_of_house`. 18 | mod front_of_house { 19 | // define another module named `hosting` within the front_of_house module. 20 | // 21 | // `pub` makes a definition public. 22 | // -> Without `pub`, a definition is private by default. 23 | // -> A parent can't learn details about its children. 24 | // -> A child can learn everything about its parent. 25 | pub mod hosting { 26 | pub fn add_to_waitlist() {} 27 | fn seat_at_table() {} 28 | } 29 | // define another module named `serving` within the front_of_house module. 30 | mod serving { 31 | fn take_order() {} 32 | fn serve_order() {} 33 | fn take_payment() {} 34 | } 35 | } 36 | 37 | // 38 | // The `module tree` of the front_of_house crate: 39 | // 40 | // crate <- module name 41 | // └── front_of_house <- parent module 42 | // ├── hosting <- a child of front_of_house 43 | // │ ├──add_to_waitlist <- a child of hosting 44 | // │ └──seat_at_table <- a sibling of add_to_waitlist 45 | // └── serving <- a sibling of hosting 46 | // ├── take_order <- ... 47 | // ├── serve_order 48 | // └── take_payment 49 | // 50 | // Looks like a directory structure, eh? 51 | // Right. 52 | // You can use modules to organize your code. 53 | // Just like you can use directories to organize your files. 54 | 55 | // note: eat_at_restaurant() is a sibling to the front_of_house module. 56 | // -> they can see each other. 57 | // -> that's why you can access front_of_house from this function. 58 | pub fn eat_at_restaurant() { 59 | // How to reach out to these modules? 60 | // Absolute path (the recommended way) 61 | crate::front_of_house::hosting::add_to_waitlist(); 62 | 63 | // Relative path 64 | // This fn is also in the same crate. 65 | // So you can skip typing `crate::`. 66 | front_of_house::hosting::add_to_waitlist(); 67 | 68 | // If hosting and add_to_waitlist weren't `public` (marked with `pub`), 69 | // Then we wouldn't be able to access them here. 70 | } 71 | 72 | // ------------------------------------------------------------------------------- 73 | 74 | // this fn is defined at the crate level (root). 75 | fn serve_order() {} 76 | 77 | // this module is also defined at the crate level (root). 78 | mod back_of_house { 79 | // this fn is defined at the back_of_house module level. 80 | fn fix_incorrect_order() { 81 | // it can call another sibling fn. 82 | cook_order(); 83 | 84 | // normally, this one can't reach out to serve_order. 85 | // because, they are at different levels. 86 | // 87 | // to reach it, this fn needs to use `super`: 88 | // 89 | // super -> the parent of back_of_house -> crate 90 | // 91 | super::serve_order(); 92 | } 93 | 94 | // this fn is a sibling of fix_incorrect_order. 95 | // it's been defined in the back_of_house module level. 96 | fn cook_order() {} 97 | 98 | // -------------------------------------------------------------------------- 99 | 100 | pub struct Breakfast { 101 | // You can also declare fields as public. 102 | pub toast: String, 103 | // This one is private. 104 | seasonal_fruit: String, 105 | } 106 | 107 | impl Breakfast { 108 | // only with `summer()`, you can create Breakfast here. 109 | // because: summer is an associated fn that can access to 110 | // Breakfast internals. 111 | // To a private field like: seasonal_fruit. 112 | pub fn summer(toast: &str) -> Breakfast { 113 | Breakfast { 114 | toast: String::from(toast), 115 | seasonal_fruit: String::from("peaches"), 116 | } 117 | } 118 | // see: eat_meal() below. 119 | } 120 | 121 | // -------------------------------------------------------------------------- 122 | 123 | // When you can make an enum public, all of its variants become public. 124 | // Enums aren't very useful unless their variants are public. 125 | pub enum Appetizer { 126 | Soup, // public 127 | Salad, // public 128 | } 129 | // see: eat_appetizer() below. 130 | } 131 | 132 | // -------------------------------------------------------------------------- 133 | 134 | pub fn eat_meal() { 135 | // Order a breakfast in the summer with Rye toast 136 | let mut meal = back_of_house::Breakfast::summer("Rye"); 137 | // Change our mind about bread we'd like (toast is mutable & public) 138 | meal.toast = String::from("Wheat"); 139 | println!("I'd like {} toast please", meal.toast); 140 | 141 | // `seasonal_fruit` is private, we're not allowed to see or modify it. 142 | // meal.seasonal_fruit = String::from("blueberries"); 143 | } 144 | 145 | // this one can't create Breakfast because it cannot access the 146 | // seasonal_fruit (private) field — unlike the summer fn above. 147 | // 148 | // pub fn cant_breakfast(toast: &str) -> back_of_house::Breakfast { 149 | // back_of_house::Breakfast { 150 | // toast: String::from(toast), 151 | // seasonal_fruit: String::from("peaches"), 152 | // } 153 | // } 154 | // 155 | // Read more by running this command: 156 | // rustc --explain E0063 157 | 158 | // -------------------------------------------------------------------------- 159 | 160 | pub fn eat_appetizer() { 161 | // Soup and Salad are public so you can access them here. 162 | let order1 = back_of_house::Appetizer::Soup; 163 | let order2 = back_of_house::Appetizer::Salad; 164 | // ... 165 | } 166 | 167 | // -------------------------------------------------------------------------- 168 | 169 | pub fn eat_at_restaurant_verbose() { 170 | // 171 | // Using the fn like this is kind of cumbersome and repetitive: 172 | // 173 | crate::front_of_house::hosting::add_to_waitlist(); 174 | front_of_house::hosting::add_to_waitlist(); 175 | } 176 | 177 | // There is a better way. 178 | // Let's bring the hosting module to this scope. 179 | use crate::front_of_house::hosting; 180 | // ^ ^ ^ 181 | // | | | 182 | // create module name child of 183 | // name front_of_house module 184 | 185 | pub fn eat_at_restaurant_concise() { 186 | // And then you can call the definitions as if they're local: 187 | hosting::add_to_waitlist(); 188 | hosting::add_to_waitlist(); 189 | hosting::add_to_waitlist(); 190 | } 191 | 192 | // -------------------------------------------------------------------------- 193 | 194 | // 195 | // 😡UNIDIOMATIC: 196 | // 197 | // Don't bring a fn into scope with use. 198 | // 199 | // use crate::front_of_house::hosting::add_to_waitlist; 200 | // 201 | // 202 | // 🥳 IDIOMATIC: 203 | // 204 | // Bringing the function's parent module into scope with use so 205 | // so we have to specify the parent module when calling the function: 206 | // -> makes it clear that the function isn't locally defined 207 | // -> while still minimizing repetition of the full path. 208 | // 209 | // use crate::front_of_house::hosting; 210 | // 211 | // pub fn eat_at_restaurant_concise() { 212 | // ★ It's clear that add_to_waitlist is an external fn. 213 | // ★ And it belongs to the hosting module. 214 | // 215 | // hosting::add_to_waitlist(); 216 | // } 217 | // 218 | // 219 | // However, it is 🥳 IDIOMATIC to bring structs, enums, and other items with use: 220 | // 221 | // This brings Hashmap struct into the scope. 222 | // 223 | // use std::collections::HashMap; 224 | // 225 | // fn main() { 226 | // let mut map = HashMap::new(); 227 | // map.insert(1, 2); 228 | // } 229 | // 230 | // If there is a clash, this is the 🥳 IDIOMATIC way: 231 | // 232 | // use std::fmt::Result; <- Result is still Result 233 | // use std::io::Result as IoResult; <- Result becomes IoResult 234 | // 235 | 236 | // -------------------------------------------------------------------------- 237 | 238 | // RUST FACADE PATTERN: RE-EXPORTING 239 | // 240 | // Re-exporting is useful when the internal structure of your code 241 | // is different from how programmers calling your code would think 242 | // about the domain. 243 | // 244 | // mod front_of_house { 245 | // pub mod hosting { 246 | // pub fn add_to_waitlist() {} 247 | // } 248 | // } 249 | // pub use crate::front_of_house::hosting; 250 | // 251 | // This way, external code can reach out to definitions like this: 252 | // 253 | // hosting::add_to_waitlist 254 | // 255 | 256 | // -------------------------------------------------------------------------- 257 | 258 | // 👉 `std`, the Standard Library crate is also external to any other packages. 259 | 260 | // -------------------------------------------------------------------------- 261 | 262 | // NESTED `use` to clean up large `use` lists. 263 | 264 | // 265 | // 😡 Verbose: 266 | // 267 | // use std::cmp::Ordering; 268 | // use std::io; 269 | // 270 | // 🥳 Concise: 271 | // 272 | // use std::{cmp::Ordering, io}; 273 | // 274 | // You can use self to refer to the same package. 275 | // 276 | // 😡 Verbose: 277 | // 278 | // use std::io; 279 | // use std::io::Write; 280 | // 281 | // 🥳 Concise: 282 | // 283 | // use std::io::{self, Write}; 284 | // 285 | -------------------------------------------------------------------------------- /rpl/_11_collections/src/strings.rs: -------------------------------------------------------------------------------- 1 | // =================================================================== 2 | // 🤯 OMG 3 | // I had a hard time learning through all of these String types. 4 | // When I try to do the collection exercises, I couldn't know what to do. 5 | // So I tried to reread the documentation, and also a lot of posts, etc. 6 | // I think I finally came to understand the necessary knowledge to go on. 7 | // =================================================================== 8 | 9 | // =================================================================== 10 | // ☝️ Rust wants you to put more thought when working with Strings. 11 | // So that you'll be saved from string/character bugs later on. 12 | // =================================================================== 13 | 14 | // =================================================================== 15 | // ☝️ When Rustaceans refer to "strings" in Rust, 16 | // they usually mean the String and the string slice &str types, 17 | // not just one of those types. 18 | // =================================================================== 19 | 20 | // =================================================================== 21 | // String Terminology used in Rust: 22 | // 23 | // ❤️ TLDR: 24 | // 25 | // -> Use `String`: If you need an owned and mutable string data. 26 | // -> use `&str` : If you need a borrowed, and read-only string data. 27 | // 28 | // ⭐️ "a string literal like this one" 29 | // 30 | // -> A fix-sized UTF-8 encoded string slice that refers to a 31 | // hardcoded location in memory. 32 | // -> Underlying type: &'static str 33 | // -> `'static` means the value is hardcoded into the binary. 34 | // 35 | // ⭐️ &str 36 | // 37 | // -> Preferred way to pass strings around. 38 | // -> Called a string slice. 39 | // -> It gets copied (not cloned). 40 | // 41 | // -> UTF-8 encoded: It's a reference to a UTF-8 byte array. 42 | // 43 | // => Two-words fat pointer: 44 | // -> A pointer to a `str`. 45 | // -> The str's length. 46 | // -> See: https://doc.rust-lang.org/std/primitive.str.html#representation 47 | // 48 | // => Size is only known at runtime. 49 | // 50 | // -> Following won't work because the size is unknown at compile-time. 51 | // Rust needs to know the size of every variable. 52 | // 53 | // let impossible: str = "nope"; 54 | // 55 | // -> This will work because &str is a reference to a location 56 | // in memory. So its address can be known at runtime. 57 | // 58 | // let possible: &str = "yep"; 59 | // 60 | // ⭐️ String 61 | // 62 | // -> Dynamic string type: Growable, and shrinkable. 63 | // -> Owned, mutable, UTF-8 encoded, and heap-allocated. 64 | // 65 | // -> Its source code looks like this: 66 | // 67 | // pub struct String { 68 | // vec: Vec, 69 | // } 70 | // 71 | // => You can pass it as &String to a function that accepts &str. 72 | // WHY? 73 | // https://doc.rust-lang.org/std/string/struct.String.html#deref 74 | // 75 | // 76 | // let s = String::from("hey"); 77 | // 78 | // fn p(s: &str) { 79 | // println!("{}", s); 80 | // } 81 | // 82 | // p(&s); 83 | // ^ 84 | // | 85 | // ________/ 86 | // \ Above, Rust automatically does this: 87 | // &*s 88 | // ^^ 89 | // || 90 | // |+--> Dereferences to str 91 | // +--> Borrows it 92 | // 93 | // So it becomes a &str that points to the contents of s. 94 | // 95 | // ⭐️ Other String Types 96 | // 97 | // -> OsString, OsStr, CString, and Cstr. 98 | // -> Other crates can create their own string types 99 | // to encode data, or represent data in memory 100 | // in different ways. 101 | // =================================================================== 102 | 103 | #[allow(unused)] // see: https://kutt.it/Qh9Jfb 104 | pub fn run() { 105 | // ------------------------------------------------------------------------ 106 | // let's create a new empty String 107 | // ------------------------------------------------------------------------ 108 | let mut s = String::new(); 109 | 110 | // ------------------------------------------------------------------------ 111 | // let's init another s with data 112 | // ------------------------------------------------------------------------ 113 | let data = "initial data"; 114 | let s = data.to_string(); // converts to a String. 115 | // if the type implements the Display trait. 116 | 117 | // ------------------------------------------------------------------------ 118 | // let's init it using a string literal 119 | // ------------------------------------------------------------------------ 120 | let s = "initial data".to_string(); 121 | // or you can use the `from` fn, it's the same with the one above 122 | let s = String::from("initial data"); 123 | 124 | // ------------------------------------------------------------------------ 125 | // ☝️ many ops available with Vec are available with String as well. 126 | // ------------------------------------------------------------------------ 127 | 128 | // ------------------------------------------------------------------------ 129 | // updating 130 | // ------------------------------------------------------------------------ 131 | let mut s = "hello".to_string(); 132 | let s2 = " world"; 133 | s.push_str(s2); // push_str mutably borrows s2 134 | s += ", how are you"; // ___________/ 135 | // / 136 | s.push('?'); // v 137 | println!("s: {} - s2: {}", s, s2); // so you can still use it 138 | 139 | // ------------------------------------------------------------------------ 140 | // let's concat two strings 141 | // ------------------------------------------------------------------------ 142 | let hello = "hello".to_string(); 143 | let world = " world!".to_string(); 144 | // 145 | // hello moves below, so it cannot be used again. 146 | // 147 | // this is because, the op below uses the add method of `hello`. 148 | // that method takes ownership of `hello`, and borrows `world`. 149 | // 150 | let hello_world = hello + &world; 151 | // 152 | // that's why you can no longer use hello. 153 | // 154 | // println!("{} {}", hello, world); // error: 0382 155 | // 156 | // this happens in the name of efficiency. 157 | // -> add method COPIES `world` to `hello`'s buffer. 158 | // -> so it REUSES `hello`'s buffer to prevent creating a new string 159 | // each time you concat a string to it. 160 | 161 | // ------------------------------------------------------------------------ 162 | // let's combine multiple strings (2+) using `format!()` 163 | // ------------------------------------------------------------------------ 164 | // -> format doesn't take any ownership. 165 | // -> it just prints the contents to the screen. 166 | // -> it doesn't make any concatenation. 167 | let tic = "tic".to_string(); 168 | let tac = "tac".to_string(); 169 | let toe = "toe".to_string(); 170 | let tic_tac_toe = format!("{}-{tac}-{}", tic, toe, tac = tac); 171 | // let tic_tac_toe = format!("{}-{}-{}", tic, tac, toe); // same as above 172 | println!("{}", tic_tac_toe); 173 | 174 | // ------------------------------------------------------------------------ 175 | // what about utf-8? 176 | // ------------------------------------------------------------------------ 177 | // rust counts how many bytes needed to represent a UTF-8 string. 178 | // -> for example: ü and ı are 2 bytes each. 179 | println!("len(\"Gunaydin\") : {} bytes", "Gunaydin".len()); // 8 bytes 180 | println!("len(\"Günaydın\") : {} bytes", "Günaydın".len()); // 10 bytes 181 | 182 | // let's count the characters (scalar values) instead. 183 | println!( 184 | "\"Günaydın\".chars().count(): {} chars", 185 | "Günaydın".chars().count() 186 | ); // 8 187 | 188 | // ------------------------------------------------------------------------ 189 | // let's index a string, think twice. 190 | // ------------------------------------------------------------------------ 191 | // 🦀 TLDR: "string indexing is a bad idea!" 192 | // 193 | // Example: 194 | // 195 | // "Günaydın"[1] 196 | // 197 | // ü is two bytes, so why do you want the first byte? it doesn't make sense. 198 | // bailout! 199 | // 200 | // But, why? 201 | // 202 | // -> the return type isn't clear: a char? a grapheme cluster? idk. 203 | // -> to prevent unexpected values. 204 | // -> to prevent possibly-buggy code. 205 | // -> to make it possible to guarantee O(1) performance. 206 | // -> string indexing is usually O(1). 207 | // -> however, often that may not be true for multiple-byte chars. 208 | // -> to leave the interpretation and storing raw string data to you, the programmer. 209 | // 210 | 211 | // So what should you do? 212 | // -> Use proper ranges to get a slice. 213 | // -> For example: ü is consisting of 2 bytes, within this range: 1..3 214 | let s = "Günaydın"; 215 | println!("Günaydın[0..1] = {}", &"Günaydın"[0..1]); // G 216 | println!("Günaydın[1..3] = {}", &"Günaydın"[1..3]); // ü 217 | // ⭐️ Remember: & is for borrowing. 218 | 219 | // PANIC ERROR: 1..2 is the first byte of ü. 220 | // -> Rust can't give you a slice like that. 221 | // println!("Günaydın[0..1] = {}", &"Günaydın"[1..2]); 222 | 223 | // ------------------------------------------------------------------------ 224 | // let's iterate 225 | // ------------------------------------------------------------------------ 226 | let s = "Günaydın"; 227 | for c in s.chars() { 228 | println!("{}", c); 229 | } 230 | // Behind the scenes: s.chars() calls s.as_bytes().iter() {} 231 | 232 | // If you want to see the individual bytes, use the `s.bytes()` instead. 233 | for b in s.bytes() { 234 | println!("{}", b); 235 | } 236 | 237 | // 238 | // What does Rust iterate on with the chars() method? 239 | // 240 | // -> chars() iterates over Unicode scalar values. 241 | // 😡 Is it weird? Kinda. 242 | // 243 | // -> Iteration over grapheme clusters may be what you actually want. 244 | // -> This functionality is not provided by Rust's standard library, 245 | // -> Check crates.io instead. 246 | // 247 | // What's a grapheme cluster? 248 | // 249 | // -> you can usually think of it as an ordinary alphabet letter. 250 | // -> a character (_as we call it_) is a very different thing in the eyes of a computer. 251 | // 252 | // Not convinced? 253 | // 254 | // read this one: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries 255 | // and this : https://en.wikipedia.org/wiki/Character_(computing) 256 | // 257 | } 258 | 259 | // REFERENCES: 260 | // https://doc.rust-lang.org/book/ch08-02-strings.html 261 | // https://doc.rust-lang.org/std/primitive.str.html 262 | // https://doc.rust-lang.org/std/string/struct.String.html 263 | // https://doc.rust-lang.org/src/alloc/string.rs.html 264 | // https://doc.rust-lang.org/src/core/str/mod.rs.html 265 | --------------------------------------------------------------------------------