fn fizzbuzz(n: i32) { for i in 1..=n { if i % 15 == 0 { println!("FizzBuzz"); } else if i % 5 == 0 { println!("Buzz"); } else if i % 3 == 0 { println!("Fizz"); } else { println!("{i}"); } } } // Associated functions (without self) and Methods (with self) // are the ways of connecting a function to a type. struct Point { x: i8, y: i8, } impl Point { // Associated functions fn origin() -> Point { Point { x: 0, y: 0 } } fn new(x: i8, y: i8) -> Point { Point { x, y } } // Methods fn run(&mut self, x: i8, y: i8) { self.x += x; self.y += y; } // bad practice, just for practice fn to_string(&self) -> String { format!("{} {}", self.x, self.y) } } // when used as a parameter in a function // the closures complete type must be annotated using one of a few traits. // In order to decrease restriction, they are: // Fn: the closure uses the captured value by reference (&T) // FnMut: the closure uses the captured value by mutable reference (&mut T) // FnOnce: the closure uses the captured value by value (T) // // NOTE: this function could also take a normal function as a parameter, not only a closure fn apply(f: F) where F: FnOnce(), { println!("About to run a closure..."); f(); } fn create_fn() -> impl Fn() { let text = "Fn".to_owned(); move || println!("Info: {}", text) // move converts the used variables to variables captured by // value; } fn divergin_one() -> ! { panic!("This will never return! PANIC"); } pub fn functions_module() { fizzbuzz(10); println!("-- Associated functions and Methods --"); let mut my_point = Point::new(4, 5); println!("My point: {}", my_point.to_string()); my_point.run(20, 1); println!("My point: {}", my_point.to_string()); // Closures are made to allow access to the enclosing environment, // similar to JS functions inside functions let mut closure_run = |x: i8, y: i8| { my_point.x += x; my_point.y += y; }; closure_run(10, 15); println!("My point: {}", my_point.to_string()); // closure_run(10, 15); // println!("My point: {}", my_point.to_string()); // move keyword forces the closure to take ownership of captured variables let mut closure_run = move |x: i8, y: i8| { my_point.x += x; my_point.y += y; }; // Rust provides higher order functions, such as // - map : .map(|n| n * n) // - filter : .filter(|&n| is_add(n)) // - take_while : .take_while(|&n| n < upper) // Diverging functions // Never return, marked with: ! // Useful on divergin situations where an exact type is required for i in 0..5 { let value: u32 = match i % 2 == 0 { true => 5, false => continue, }; println!("The value is pair and {value}"); } // NOTE: Bad example since it's not really useful divergin_one(); }