diff --git a/docs/rust/advanced/closures.md b/docs/rust/advanced/closures.md new file mode 100644 index 0000000..da00127 --- /dev/null +++ b/docs/rust/advanced/closures.md @@ -0,0 +1,65 @@ +# Closures + +Closures are anonymous functions that capture the scope in which they are defined. They can be saved as a variable or passed into a function. + +```rust +struct HelloWorld { + msg: String +} +impl HelloWorld { + fn test_closure(&self, name: Option<&str>) -> String { + String::from(format!(self.msg, name.unwrap_or_else(|| self.default_name()))) + } + + fn default_name() -> String { + return String::from("David") + } +} + +// Example with parameter and return value +let expensive_closure = |num: u32| -> u32 { + println!("calculating slowly..."); + thread::sleep(Duration::from_secs(2)); + num +}; +``` + +## Ownership and References + +### Immutable reference + +```rust +let list = vec![1, 2, 3]; +println!("Before defining closure: {:?}", list); + +let only_borrows = || println!("From closure: {:?}", list); + +println!("Before calling closure: {:?}", list); +only_borrows(); +println!("After calling closure: {:?}", list); +``` + +### Mutable reference + +```rust +let mut list = vec![1, 2, 3]; +println!("Before defining closure: {:?}", list); + +let mut borrows_mutably = || list.push(7); + +borrows_mutably(); +println!("After calling closure: {:?}", list); +``` + +### Take ownership with `move` + +```rust +use std::thread; + +let list = vec![1, 2, 3]; +println!("Before defining closure: {:?}", list); + +thread::spawn(move || println!("From thread: {:?}", list)) + .join() + .unwrap(); +``` \ No newline at end of file diff --git a/docs/rust/advanced/tests.md b/docs/rust/advanced/tests.md new file mode 100644 index 0000000..6ad15b4 --- /dev/null +++ b/docs/rust/advanced/tests.md @@ -0,0 +1,75 @@ +# Testing + +Test functions are defined with the `#[test]` attribute. Within the tests, we use the `assert!` macro to evaluate a boolean and fail the tests if it does not pass. You can also use `assert_eq!` and `assert_ne!` to test equality directly, however the values being tested must implement `PartialEq` and `Debug` traits. + +## Unit Tests + +For unit tests, its best to write your tests in the file that it is testing but contain it with a `mod tests` with the `cfg(test)` attribute. This will exclude it from the final executable or library. Unit tests also allow you to test private functions, meaning ones that are not `pub`. + +```rust +#[cfg(test)] +mod tests { + use super::*; // Use this to call functions in the current file + + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + assert!(result == 4); + } + + #[test] + fn greeting_contains_name() { + let result = greeting("Carol"); + // Custom failure message + assert!( + result.contains("Carol"), + "Greeting did not contain name, value was `{}`", + result + ); + } + + // Will pass if test panics + #[test] + #[should_panic] + fn greater_than_100() { + // Something illegal + } +} +``` + +## Integration Tests + +Integration tests live in a separate `tests` directory at the base of the project. These should test your library from a black box perspective, meaning you use it the same way a consumer would. You do not need to wrap integration tests with a `mod tests` and `#[cfg(tests)]` because they are automatically excluded from the build. To include files that provide common functionality to tests but are not tests themselves, you need to make them a module by creating a directory with a `mod.rs` (ex. `tests/common.mod.rs`). + +```rust +use adder; // our lib + +mod common; + +#[test] +fn it_adds_two() { + common::setup(); + assert_eq!(4, adder::add_two(2)); +} +``` + +## Documentation Tests + +You can define documentation comments with `///` which allows you to provide markdown that gets built into an HTML documentation. If you create code blocks, you can write valid rust code and even add assertions to create tests. These will run when you `cargo test`. + +```rust +/// Adds one to the number given. +/// +/// # Examples +/// +/// ``` +/// let arg = 5; +/// let answer = my_crate::add_one(arg); +/// +/// assert_eq!(6, answer); +/// ``` +pub fn add_one(x: i32) -> i32 { + x + 1 +} +``` \ No newline at end of file diff --git a/docs/rust/advanced/traits.md b/docs/rust/advanced/traits.md index 427417e..351cc65 100644 --- a/docs/rust/advanced/traits.md +++ b/docs/rust/advanced/traits.md @@ -91,6 +91,8 @@ fn some_function(t: &T, u: &U) -> i32 ## Returning types that implement traits +You can only use a trait as a return value if you are returning a single type. + ```rust fn returns_summarizable() -> impl Summary { Tweet { diff --git a/docs/rust/basics/errors.md b/docs/rust/basics/errors.md index 0d5c9d0..e42bb56 100644 --- a/docs/rust/basics/errors.md +++ b/docs/rust/basics/errors.md @@ -42,7 +42,12 @@ let greeting_file = match greeting_file_result { ```rust let greeting_file = File::open("hello.txt").unwrap(); -let greeting_file = File::open("hello.txt")e.expect("hello.txt should be included in this project"); +let greeting_file = File::open("hello.txt").expect("hello.txt should be included in this project"); +``` + +You can also use `unwrap_or_else` and pass a closure to return a value if something goes wrong. +```rust +let greeting_file = File::open("hello.txt").unwrap_or_else(|| None ) // return something else ``` ### Propagate an error diff --git a/docs/rust/index.md b/docs/rust/index.md index 3b4f611..0012510 100644 --- a/docs/rust/index.md +++ b/docs/rust/index.md @@ -1,2 +1,9 @@ # Rust +## Todo + +- Pointers +- Macros +- Iterators +- Closures (finish) +- Threads \ No newline at end of file diff --git a/docs/rust/sidebar.json b/docs/rust/sidebar.json index cf17c24..8859879 100644 --- a/docs/rust/sidebar.json +++ b/docs/rust/sidebar.json @@ -18,7 +18,9 @@ "text": "Advanced", "items": [ {"text": "Generics", "link": "/rust/advanced/generics"}, - {"text": "Traits", "link": "/rust/advanced/traits"} + {"text": "Traits", "link": "/rust/advanced/traits"}, + {"text": "Tests", "link": "/rust/advanced/tests"}, + {"text": "Closures", "link": "/rust/advanced/closures"} ] } ] \ No newline at end of file