use std::env; fn main() { let args: Vec = env::args().collect(); match args.len() { 1 => main1(), 2 => main10(), 3 => main100(), 4 => main101(), 5 => main1000(), _ => main1() // default } } // anonymous functions are first class. They can be set, passed and returned fn main1() { let ff = ret_fun(5); let gg = |xx:i32| { println!("{}", ff(xx)); }; gg(20); rec_fun(ff, 10); //rec_fun2(gg, 10); } fn ret_fun(tt:i32) -> fn(i32)->i32 { |x:i32| -> i32 { x*x} } fn rec_fun(fun:fn(i32)->i32, val: i32) { println!("{}", fun(val)); } fn rec_fun2(fun:fn(i32), val: i32) { fun(val); } // anon functions with closures are problematic with respect to ownership // here, because the function borrows_mutably can change the var list, nothing else // can borrow list while borrows_mutably exists. fn main10() { let mut list = vec![1, 2, 3]; println!("Before defining closure: {:?}", list); let mut borrows_mutably = || list.push(7); //println!("{:?}", list); // NOT allowed borrows_mutably(); borrows_mutably(); // to allow the print to work, the compiler must implicitly add a scope block around borrows_mutably println!("After calling closure: {:?}", list); } #[derive(Debug)] struct Rectangle { width: u32, height: u32, } fn main100() { let mut list = [ Rectangle { width: 10, height: 1 }, Rectangle { width: 3, height: 5 }, Rectangle { width: 7, height: 12 }, ]; let mut num_sort_operations = 0; list.sort_by_key(|r| { num_sort_operations += 1; r.width }); println!("{:#?}, sorted in {num_sort_operations} operations", list); } // this is identical to main100 except that the comparator function is bound to a var before use. fn main101() { let mut list = [ Rectangle { width: 10, height: 1 }, Rectangle { width: 3, height: 5 }, Rectangle { width: 7, height: 12 }, ]; let mut num_sort_operations = 0; let comp = |r: &Rectangle| { num_sort_operations += 1; r.width }; list.sort_by_key(comp); println!("{:#?}, sorted in {num_sort_operations} operations", list); } // iterators == doing things functionally fn main1000() { let vv: Vec = vec![1,2,3,4,5,6,7,8,9]; let mut summ = 0; // this is the imperative way of doing something functional vv.iter().for_each(|v| { summ = summ + v}); println!("Sum {}", summ); // this is the functional way -- the language defines a sum function summ = vv.iter().sum(); println!("Sum {}", summ); // functional way to sum squares -- first transform list into list of squares, then sum // note that map returns an iterator! // so to get the squares as a vector let sqs : Vec = vv.iter().map(|x| x*x).collect(); println!("{:?}", sqs); // another iterator function -- filtering. Keeps the things for which the boolean returns true. // trick, since the things are literally the same as in the original, we have an ownership problem. // two variables cannot own the same object. So after filter we call cloned() to make all new instances. // Again need collect() as the result of cloned() is an iterator. (note copied() works as an alternative to cloned()). What is difference between clone and copy) let evns : Vec = vv.iter().filter(|x: &&i32| *x%2==0).copied().collect(); // a different approach to the double ownership problem. Here, "into_iter()" takes ownership of vv. So // after filtering there is only one owner of each object in the resulting vector (slice) let evns : Vec = vv.into_iter().filter(|x: &i32| *x%2==0).collect(); println!("filter {:?}", evns); // here 1..9 is an iterator, so we do not need the iter() function let summ_square : i32 = (1..9).map(|x| x*x).sum(); println!("SumSq {}", summ_square); // Question which is faster?? use std::time::Instant; let now: Instant = Instant::now(); let summ_square : i128 = (1..10000000).map(|x| x*x).sum(); let elapsed = now.elapsed(); println!("Elapsed map->sum: {:.2?} {}", elapsed, summ_square); let mut summ: i128 = 0; let now: Instant = Instant::now(); (1..10000000).for_each(|v| { summ = summ + v*v}); let elapsed = now.elapsed(); println!("Elapsed foreach: {:.2?} {}", elapsed, summ); }