Chapter 1
This book was created with mdBook
It's very simple to create a book with rust, with interactive code snippets.
Everything here is created in the folder /theBook
Building the book
Just run the following command:
./build.sh
To Work on it Interactive
mdbook watch -o
Here's what's happening:
mdbook build
rm -rf ../docs
mv book ../docs
And, that's it! Here is the first example of interactive code.
fn main() { // Some code println!("Hello, world!"); }
A more advanced example
macro_rules! test { // Arguments don't need to be separated by a comma. // Any template can be used! ($left:expr; and $right:expr) => { println!("{:?} and {:?} is {:?}", stringify!($left), stringify!($right), $left && $right) }; // ^ each arm must end with a semicolon. ($left:expr; or $right:expr) => { println!("{:?} or {:?} is {:?}", stringify!($left), stringify!($right), $left || $right) }; } fn main() { test!(1i32 + 1 == 2i32; and 2i32 * 2 == 4i32); test!(true; or false); }
Useful Basic Guide
Sample with tests.
fn add_integer(a: i32, b: i32) -> i32 { a + b } fn main() { println!("{}", add_integer(1, 2)); } #[cfg(test)] mod tests { use super::*; #[test] fn test_add_integer() { assert_eq!(super::add_integer(1, 2), 3); } }
Sample with fmt skips
fn vec_vec() -> Vec<Vec<i32>> { #[rustfmt::skip] let vec = vec![ vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9], ]; vec } fn main() { let vec = vec_vec(); println!("{:?}", vec); }
Lifetimes
This gets a little more complicated. But, it's important.
We have to make sure all the variables have the same lifetime.
fn greet<'a>( names: &mut Vec<&'a str>, target_name: &'a str, custom_message: &'a str, standard_message: &'a str, ) { for name in names.iter_mut() { *name = match name { &mut n if n == target_name => custom_message, _ => standard_message, } } } fn main() { let greeting = "Well, hello Ferris!"; let mut names = vec!["Bob", "Frank", "Ferris"]; greet(&mut names, "Ferris", greeting, "hi"); println!("{:?}", names); } // Ref: // https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/lifetimes.html
Working with Files
use std::fs::File; use std::io::prelude::*; fn read_file(path: &str) -> Result<String, std::io::Error> { let mut file = File::open(path)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) } fn modify_names(names: &mut Vec<&str>, custom_message: &str) { names.iter_mut().for_each(|i| { let new_name = match *i { "Bob" => format!("{}!, What's happening?", *i), _ => format!("Hi {} {}", *i, custom_message), }; *i = Box::leak(new_name.into_boxed_str()); }); } fn main() { match read_file("./data/file.txt") { Ok(contents) => { let mut lines = contents.lines().collect(); modify_names(&mut lines, ", custom message!"); println!("{:?}", lines); } Err(e) => panic!("Error reading file: {:?}", e), } }
Working with Errors
use std::io::{Error, ErrorKind}; fn find(substring: &str) -> Result<String, Error> { let strings: Vec<String> = vec![ "apple".to_string(), "banana".to_string(), "cherry".to_string(), ]; if let Some(s) = strings.iter().find(|s| s.contains(substring)) { println!("Found '{}' in '{}'", substring, s); Ok(s.to_string()) } else { Err(Error::new( ErrorKind::NotFound, format!("No match for '{}'", substring), )) } } fn main() { let result = find("an"); if result.is_err() { println!("Error: {:?}", result.err()); } else { println!("Result: {:?}", result.unwrap()); } }
Favorite
fn main() { let strings = vec![ String::from("hello"), String::from("world"), String::from("bobcat"), String::from("bob"), String::from("alabama"), ]; let mut filtered_strings: Vec<String> = strings .iter() .filter(|s| s.contains("bob")) .inspect(|s| println!("Filtered string: {:?}", s)) .map(|s| s.clone()) .collect(); filtered_strings.sort(); println!("Filtered strings: {:?}", filtered_strings); }
Here's another one
fn main() { let strings = vec![ String::from("hello"), String::from("world"), String::from("bobcat"), String::from("bob"), String::from("alabama"), ]; let mut filtered_strings: Vec<String> = strings .iter() .filter_map(|s| { if s.contains("bob") { Some(s.clone()) } else { None } }) .collect(); filtered_strings.sort(); println!("Filtered strings: {:?}", filtered_strings); }
Useful
This can also be useful
fn main() { let numbers = vec![1, 2, 3, 4, 5]; if let Some(third_number) = numbers.iter().nth(2) { println!("The third number is {}", third_number); } else { println!("There is no third number."); } }
There's more
fn main() { let strings = vec![ String::from("hello"), String::from("world"), String::from("bobcat"), String::from("bob"), String::from("alabama"), ]; let mut filtered_strings: Vec<String> = strings .iter() .filter(|s| s.contains("bob")) .inspect(|s| println!("Filtered string: {:?}", s)) .filter(|s| sporky(s)) .map(|s| s.clone()) .collect(); filtered_strings.sort(); println!("Filtered strings: {:?}", filtered_strings); } fn sporky(string: &str) -> bool { if string.contains("cat") { println!("{} is sporky", string); true } else { println!("{} is not sporky", string); false } }
You gotta love maps
fn main() { let strings = vec![ String::from("1 2 3 4"), String::from("hello world"), String::from("goodbye world"), String::from("hello bobcat"), String::from("goodbye bobcat"), String::from("hello alabama"), String::from("goodbye alabama"), ]; let filtered_strings: Vec<String> = strings .iter() .inspect(|s| println!("Before string: {:?}", s)) .flat_map(|s| s.split_whitespace()) .inspect(|s| println!("After string: {:?}", s)) .filter(|s| s.contains("bob")) .map(|s| s.to_owned()) .collect(); println!("Filtered strings: {:?}", filtered_strings); }