Rust Programming Language

Get Started. It's Free
or sign up with your email address
Rust Programming Language by Mind Map: Rust Programming Language

1. 1. Simple Project and Cargo Project

1.1. Cargo

1.2. Simple

2. 3. Common Programming Concepts

2.1. Variables and Mutabillity

2.2. Data Types

2.3. Functions

2.4. Control Flow

2.4.1. if expression

2.4.2. loops

2.4.2.1. loop

2.4.2.2. for

2.4.2.2.1. can own a iteration value

2.4.2.3. while

3. 4. Ownership

3.1. What is it?

3.2. References and Borrowing

3.3. Slice Type

4. 5. Data Struct

4.1. concepts

4.2. implementations

4.2.1. Instantiating Structs

4.2.1.1. struct name { attributes }

4.2.2. Method Syntax

5. 6. Enum

5.1. Enum

5.1.1. concepts

5.1.2. implementations

5.1.3. option enum

5.2. "match" Control Flow

5.3. If let control flow

6. 7. Packages, Crates, and Modules

6.1. Packages and Crates

6.2. Modules

6.3. Referring item in Module Tree

6.4. "use" keyword

6.5. Separating Modules

7. 8. Common Collections

7.1. Vectors

7.1.1. concept

7.1.1.1. Can hold any type Vec<T>

7.1.1.2. Allow storing more than one value in one data structure

7.1.1.3. put value next to each other in memory

7.1.1.4. Can only store same type values

7.1.1.4.1. can be combined with enum to store multiple types

7.1.1.5. dropping a vector also drop its elements

7.1.1.6. Store data on the heap

7.1.2. Implementation

7.1.2.1. get using index, references, get

7.1.2.1.1. index

7.1.2.1.2. references

7.1.2.1.3. get

7.1.2.2. push

7.1.2.2.1. add new element onto the end of vector

7.1.2.2.2. if there isn't enough room next to each other

7.1.2.3. pop

7.1.2.3.1. remove and returns the last element

7.1.2.4. iterating

7.1.2.4.1. using for loop, as a reference

7.1.2.4.2. we have to dereference the element first if we wanted to modify it

7.2. String

7.2.1. concepts

7.2.1.1. growable, mutable, owned, UTF-8

7.2.1.1.1. let hello = String::from("Hello");

7.2.1.1.2. let hello = String::from("Dobrý den");

7.2.1.1.3. let s = String::from("السلام عليكم");

7.2.1.1.4. let hello = String::from("שָׁלוֹם");

7.2.1.2. Types

7.2.1.2.1. String

7.2.1.2.2. string slice (string literal): &str

7.2.1.2.3. and many more: see doc!

7.2.1.2.4. each types can store text in different encoding or be represented in memory in different way

7.2.1.3. Indexing

7.2.1.3.1. Rust does not allow indexing string, because it's UTF-8

7.2.1.4. Internal representation

7.2.1.4.1. Collection of bytes

7.2.1.4.2. let hello = "Здравствуйте"; this has 24 bytes

7.2.1.4.3. Rust Perspective "नमस्ते"

7.2.2. Implementations

7.2.2.1. creating a string

7.2.2.1.1. String::from()

7.2.2.1.2. using string slice: "string".to_string()

7.2.2.1.3. let s = "String string"

7.2.2.2. Updating

7.2.2.3. Slicing

7.3. HasMap

7.3.1. concepts

7.3.1.1. Stores mapping of keys of type K to values of type V: HasMap<K, V>

7.3.1.2. useful when wanted to look up data not by index

7.3.1.3. Store data on the heap

7.3.1.4. homogeneous

7.3.1.4.1. All keys must have same type, also for values

7.3.2. implementations

7.3.2.1. creating HashMap

7.3.2.1.1. use std::collections::HashMap

7.3.2.1.2. .insert(K, V); for inserting data to HashMap

7.3.2.2. Ownership

7.3.2.2.1. values and keys can be owned by HashMap

7.3.2.3. Accessing Values

7.3.2.3.1. get(&k: K)

7.3.2.3.2. for loop

7.3.2.4. Updating HashMap

7.3.2.4.1. Overwriting

7.3.2.4.2. Selective insert

7.3.2.4.3. based on old value

8. 9. Error Handling

8.1. definitions

8.1.1. Requires to acknowledge an error before the code will compile

8.1.2. recoverable: file not found error

8.1.3. unrecoverable: bugs, trying to access a location beyond the end of an array

8.1.4. Rust doesn't have exception

8.2. panic!

8.2.1. concepts

8.2.1.1. Unrecoverable Error

8.2.1.2. execute -> unwind and clean up stack -> quit

8.2.1.3. happened when a bug of some kind detected

8.2.1.4. not clear to programmer how to handle the error

8.2.2. Implementations

8.2.2.1. panic! macro

8.2.2.1.1. error message

8.2.2.1.2. location of it in files

8.2.2.2. Backtrace

8.2.2.2.1. RUST_BACKTRACE=1

8.3. Result

8.3.1. concepts

8.3.1.1. Recoverable Errors

8.3.1.2. enum Result<T, E> T stands for response and E for error

8.3.2. implementations

8.4. When to use

9. 10. Generic Types, Traits, and Lifetimes

9.1. Generic Data Types

9.1.1. concepts

9.1.1.1. can be use with many different concrete data types

9.1.1.2. permormance

9.1.1.2.1. monomorphization

9.1.1.2.2. doesn't run any slower

9.1.2. implementations

9.1.2.1. defining method

9.1.2.1.1. fn largest<T>(list: &[T]) -> T this will return T types

9.1.2.2. defining struct

9.1.2.2.1. struct Point<T> { x: T, y: T, } in this struct, x and y have same types which is T

9.1.2.2.2. struct Point<T, U> { x: T, y: U, }

9.1.2.3. defining enum

9.1.2.3.1. enum Option<T>

9.1.2.3.2. enum Result<T,E>

9.2. Traits

9.2.1. concepts

9.2.1.1. works like interface in other language

9.2.1.2. shared behavior

9.2.2. implementations

9.2.2.1. trait on a type

9.2.2.1.1. impl [trait name] for [type name] {}

9.2.2.2. trait as param

9.2.2.2.1. when parameter is some type that implement the trait

9.2.2.2.2. pub fn [name]<T: [trait]> ([varname]: T) {}

9.2.2.3. where clauses

9.2.2.3.1. pub fn [name]<T, U> ([varname]: T, [varname]: U) where T: [trait], U: [trait] {}

9.2.2.4. returning types that implement traits

9.2.2.4.1. only returning single type

9.2.2.5. traits bounds to conditionally implement methods

9.2.2.5.1. blanket implementations: implement trait for any type that implement another trait

9.3. Validating References: Generic Lifetimes Parameters

9.3.1. concepts

9.3.1.1. required us to annotate the relationships using generic lifetime parameters

9.3.1.1.1. ensure the actual references used at runtime will definitely be valid

9.3.1.2. prevent dangling references

9.3.1.3. borrow checker

9.3.1.3.1. compare scope to determine whether all borrows are valid

9.3.1.4. Elision Rules

9.3.1.4.1. each parameter that is a reference gets its own lifetime parameter

9.3.1.4.2. if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters

9.3.1.4.3. if there are multiple input lifetime parameters, the lifetime of self is assigned to all output lifetime parameters

9.3.2. implementations

9.3.2.1. using ' and name of the generic lifetime after & before type. Ex: &'a i32

10. 11. Automated Test

10.1. concepts

10.1.1. used for unit test

10.1.1.1. test each unit of code isolation from the rest of the code to quickly pinpoint where code is and isn't working as expected

10.1.2. cargo test compiles code in test mode and runs the resulting test binary

10.1.3. body of test function

10.1.3.1. Set up any needed data or state.

10.1.3.2. Run the code you want to test.

10.1.3.3. Assert the results are what you expect.

10.2. implementations

10.2.1. write test

10.2.1.1. #[test]

10.2.1.2. #[should_panic]

10.2.1.2.1. #[should_panic(expected = "[panic message]")

10.2.1.3. combine with Result<T, E>

10.2.1.4. use super::*;

10.2.1.4.1. when test module is inner module

10.2.2. control

10.2.2.1. run in parallel or consecutively

10.2.2.1.1. cargo test -- --test-thread = 1 this will tell program not to use any parallelism, running only in one thread

10.2.2.2. #[ignore]

10.2.2.3. cargo test

10.2.2.3.1. cargo test [test_name]

10.2.2.3.2. cargo test -- --nocapture

10.2.3. Organization

10.2.3.1. convention way to do unit test

10.2.3.1.1. create a module named tests in each file to contain the test function and to annotate the module with cfg(test)

10.2.3.2. #[cfg(test)]

10.2.3.2.1. tells rust to compile and run the test code only when we run cargo test.

10.2.3.2.2. cfg -> configuration

10.2.3.2.3. (test) -> configuration option

10.2.3.3. rust allow to test private fuctions

10.2.3.4. Integration Test

10.2.3.4.1. put test directory at the top level, next to src

10.2.3.4.2. if the project is binary crate (only contains src/main.rs), we cant create integration tests in the tests directory because they are meant to be run on their own

10.2.3.4.3. only library crates expose function that other crates can use

11. 13. Functional Language Features: Iterator and Closures

11.1. Closures

11.1.1. concepts

11.1.1.1. function-like construct we can store in a variable

11.1.1.2. it contains definition of a fuction, not resulting value

11.1.1.3. can be combined with generic type

11.1.1.4. can capture environtment

11.1.1.4.1. it uses memory to store the values for use in the closure body

11.1.1.5. Rust infers which trait to use based on how the closure uses the values from the environment

11.1.1.5.1. All closure implement FnOnce

11.1.1.5.2. didn't move captured variables implement FnMut

11.1.1.5.3. don't need mutable access implement Fn

11.1.1.6. only available inside scope it was defined

11.1.2. Implementations

11.1.2.1. let expensive_closure = |num| { println!("calculating slowly..."); num };

11.1.2.1.1. |...| symbol for parameters

11.1.2.1.2. can inference type

11.1.2.2. generic types

11.1.2.2.1. traits: Fn, FnMut, FnOnce

11.2. Iterator

11.2.1. concepts

11.2.1.1. way of processing a series of elements

11.2.1.2. LAZY

11.2.1.2.1. they have to perform some task on a sequence of items in turn

11.2.1.2.2. have no effect until we call methods that consume the iterator to use it up.

11.2.1.3. can be consumed

11.2.1.3.1. iter.sum()

11.2.1.3.2. looping

11.2.1.4. can produce other iterators

11.2.1.5. All iterators implement iterator trait

11.2.2. implementations

11.2.2.1. type

11.2.2.1.1. iter

11.2.2.1.2. into_iter

11.2.2.1.3. iter_mut

11.2.2.2. create iterator

11.2.2.2.1. let iter = collection.iter()

11.2.2.3. looping

11.2.2.3.1. for loop

11.2.2.3.2. next

11.2.2.4. filter

11.2.2.4.1. it takes a closure that takes each item from the iterator and returns a boolean

11.2.2.5. creating iterator using iterator trait

11.2.2.5.1. we can define what the iterator will do, ex. defining what next method will do

11.2.2.6. closure

11.2.2.6.1. filter

12. 14. Cargo and Crates.io

13. 15. Smart Pointers

13.1. definitions

13.1.1. pointers

13.1.1.1. example in rust is reference

13.1.1.2. don't have any special capabilities other than referring to data

13.1.1.3. don't have any overhead

13.1.1.4. variable that contains an address in memory

13.1.2. smart pointers

13.1.2.1. have additional metadata and capabillities

13.1.2.2. they own the data they point to

13.1.2.3. String and Vec<T> are smart pointers

13.1.2.3.1. both own some memory and allow us to manipulate it.

13.1.2.3.2. have metadatas: capacity, and ensuring its data will always be valid UTF-8 (for String)

13.1.2.4. Usually implemented using structs

13.1.2.4.1. implement Deref and Drop traits

13.2. Common Smart Pointers

13.2.1. Box<T>

13.2.1.1. concepts

13.2.1.1.1. Store data on the heap

13.2.1.1.2. box is pointer, therefore stored on the stack

13.2.1.1.3. since box is pointer, rust know how much space a box needs because a pointer size doesn't change based on the amount of data it's pointing to.

13.2.1.2. implementation: recursive types

13.2.1.2.1. without box

13.2.1.2.2. with box

13.2.2. Deref Trait

13.2.2.1. concepts

13.2.2.1.1. by implementing it, a smart pointer can be treated like a regular reference

13.2.2.1.2. we can write code that operates on references and use that code with smart pointers

13.2.2.1.3. following pointer to the value

13.2.2.1.4. deref method BORROWS self and returns a reference to the INNER DATA

13.2.2.2. implementations

13.2.2.2.1. assert_eq!(5, *y);

13.2.2.2.2. deref coercion

13.2.3. Drop Trait

13.2.3.1. concepts

13.2.3.1.1. included in the prelude

13.2.3.1.2. can provide an imlementation for the drop trait on any type

13.2.3.1.3. can put logic to execute when an instance goes out of scope

13.2.3.2. implementation

13.2.3.2.1. requires us to implement one method named drop that takes a mutable reference to self

13.2.3.2.2. Dropping a Value Early with std::mem::drop

13.2.4. Rc: Reference Counted

13.2.4.1. The Rc<T> type keeps track of the number of references to a value to determines wheteher or not a value is still in use

13.2.4.1.1. if == 0 -> the value can be cleaned

13.2.4.1.2. ensure that destructors are called for shared data

13.2.4.2. only for use in single threaded scenarios

13.2.4.3. shares ownership of data on the heap

13.2.4.3.1. readonly data

13.2.4.4. implementation

13.2.4.4.1. count

13.2.5. RefCell<T>

13.2.5.1. does not allocate, but it contains an additional “borrow state” indicator (one word in size) along with the data.

13.2.5.2. RefCell<T> enforces the read-write lock pattern at runtime (it’s like a single-threaded mutex)

13.2.5.2.1. borrow() and borrow_mut()

13.2.5.3. borrowing rules enforced at runtime

13.2.5.3.1. when we break the rules, it will panic

13.2.5.4. only for single threaded scenarios

13.2.6. Dealing with reference cycles

13.2.6.1. by turning Rc<T> to Weak<T>

13.2.6.1.1. upgrade

13.2.6.1.2. downgrade

14. 16. Concurrency

14.1. thread::spawn

14.1.1. move closure

14.1.1.1. take ownership of an instance from main thread

14.1.1.2. thread take closure with 0 parameters

14.1.1.3. syntax: move || {}

14.1.2. join handles

14.1.2.1. calling join() block the thread currently running until the thread represented by the handle terminates

14.1.2.2. block means the thread prevented from performing work or exiting

14.1.3. thread will end when the main tread ends

14.2. message passing: channel multiple producer single consumer (mpsc)

14.2.1. transmitter

14.2.2. receiver

14.2.2.1. recv

14.2.2.1.1. will block main thread's execution and wait untul a value is sent down the channel

14.2.2.1.2. recv will return a Result<T,E>

14.2.2.2. try_recv

14.2.2.2.1. doesn't block but will return a Result<T,E> immediatly

14.2.2.2.2. useful if this thread has other work to do while waiting for messages

14.3. Mutex: Shared-state Concurrency

14.3.1. it's like multiple ownership: multiple threads can access the same memory location at the same time

14.3.2. mutex

14.3.2.1. only allows one thread to access some data at any given time

14.3.2.2. access data

14.3.2.2.1. thread must first signal that it wants access by asking to acquire the mutex's lock

14.3.2.2.2. lock

14.3.2.3. rules

14.3.2.3.1. we must attempt to acquire the lock before using the data

14.3.2.3.2. when we're done with the data, we must unlock the data so other threads can acquire the lock

14.3.2.3.3. Rust type system and ownership rules, we can't get locking and unlocking wrong

14.3.2.4. example

14.3.2.4.1. use std::sync::Mutex; fn main() { let m = Mutex::new(5); { let mut num = m.lock().unwrap(); *num = 6; } println!("m = {:?}", m); }

14.3.2.4.2. use Arc<T>