feat: multiple lessons

This commit is contained in:
2025-02-22 11:57:50 +01:00
parent 47313f061e
commit 266bd1e125
4 changed files with 222 additions and 14 deletions

103
src/macros.rs Normal file
View File

@@ -0,0 +1,103 @@
// Group functionality with different types
// Define special syntac for specific purpose
// Variable number of arguments
// Different combination of arguments
macro_rules! say_hello {
() => {
println!("Hello world!");
};
}
// Types of arguments have designators:
// block
// expr is used for expressions
// ident is used for variable/function names
// item
// literal is used for literal constants
// pat (pattern)
// path
// stmt (statement)
// tt (token tree)
// ty (type)
// vis (visibility qualifier)
macro_rules! generate_function {
($func_name:ident) => {
fn $func_name() {
println!("You called {:?}()", stringify!($func_name));
}
};
}
generate_function!(foo);
macro_rules! process_expression {
($expression: expr) => {
println!("{:?} = {:?}", stringify!($expression), $expression);
};
}
// Overload
macro_rules! match_block {
($left: expr; and $right: expr) => {
println!("A: {:?} and {:?}", stringify!($left), stringify!($right))
};
($left: expr; or $right:expr) => {
println!(
"B: {:?} or {:?} is {:?}",
stringify!($left),
stringify!($right),
$left || $right
)
};
}
// Repeat: variable number of args o a type
macro_rules! find_max {
($x:expr) => ($x);
($x:expr, $($y:expr), +) => (std::cmp::max($x, find_max!($($y), +)));
}
// DSLs: Domain Specific Languages
// macro_rules allows you to create your own syntax
macro_rules! calc {
(eval $e:expr) => {
println!("{} = {}", stringify!($e), $e);
};
}
macro_rules! calculate {
(eval $e: expr) => {
{
let val: usize = $e; // Force types to be integers
println!("{} = {}", stringify!{$e}, val);
}
};
(eval $e: expr, $(eval $y: expr), +) => {{
calculate!{eval $e}
calculate!{ $(eval $y), + }
}};
}
pub fn macros_rule() {
foo();
say_hello!();
process_expression!(1 + 5 * 3);
match_block!(1i32 + 1 == 2i32; and 2i32 * 2 == 4i32); // Enters first branch
match_block!(true; or false); // Enter second branch
match_block!(true; and true); // Enters first branch
println!("Max is {}", find_max!(5, 3 * 8, 4, 9 * 5));
calc! {
eval (1 + 2) * 4
}
calculate! {
eval (1 + 2) * 4,
eval 1 + 5,
eval 7 + 4,
eval 3 + 9
}
}

View File

@@ -5,18 +5,8 @@
// : /// Doc comment: generate library docs for the following item
// : //! Doc comment
// mod helloworld;
// mod primitives;
// mod customtypes;
//mod variablebindings;
// mod types;
//mod conversion;
// mod controlflow;
// mod traits;
// mod str_types;
// mod functions;
// mod exercises;
mod concepts;
mod macros;
use macros::macros_rule;
#[cfg(test)]
#[path = "./test/basic_test.rs"]
@@ -30,10 +20,12 @@ fn main() {
//types::types_module();
//conversion::conversion_module();
// controlflow::control_flow_module();
//traits::traits_exercise();
// traits::traits_exercise();
// str_types::str_types_module();
// exercises::run_easy();
// my_lib::public_function();
// functions::functions_module();
concepts::box_basics();
// concepts::box_basics();
// operators::operators_module();
macros_rule();
}

24
src/operators.rs Normal file
View File

@@ -0,0 +1,24 @@
use std::ops;
use std::ops::Add;
/*
* Operators are syntectic sugar for method calls
* The + operator calls the add method and so on
* */
pub fn operators_module() {
let a = 3u32.add(3);
println!("a is {a}");
// Operator overloading
struct Foo;
impl ops::Add<u32> for Foo {
type Output = Foo;
fn add(self, rhs: u32) -> Self::Output {
println!("> add called with {}", rhs);
Foo
}
}
let foo = Foo;
let _too = foo + 3; // > add called with 3
}

View File

@@ -6,6 +6,8 @@
* 4. Extend the trait with a second function and see what happens
* */
use std::thread::current;
pub trait Move {
fn to(&mut self, x: i32, y: i32);
}
@@ -32,4 +34,91 @@ pub fn traits_exercise() {
me.to(10, 20);
println!("My name is {} and i'm at {:?}", me.name, me.position);
// Drop trait: called with an object goes out of scope
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo went out of scope...");
}
}
let mut counter = 0u32;
loop {
if counter > 5 {
break;
}
counter += 1;
let _foo = Foo;
}
// Iterator traits
// Example: Fibonacci
struct Fibonacci {
current: u32,
next: u32,
}
impl Iterator for Fibonacci {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
let current = self.current;
self.current = self.next;
self.next = self.next + current;
Some(current)
}
}
let mut fib = Fibonacci {
current: 0,
next: 1,
};
for _ in 0..21 {
println!("Fib {:?}", fib.next());
}
let mut fib = Fibonacci {
current: 0,
next: 1,
};
println!("Fib 20 {:?}", fib.nth(20));
let fib = Fibonacci {
current: 0,
next: 1,
};
println!("Fib skip 20 {:?}", fib.skip(20).next());
// Disambiguating overlapping traits
struct Fee {
a: u32,
b: String,
}
trait A {
fn get(&self) -> u32;
}
trait B {
fn get(&self) -> String;
}
impl A for Fee {
fn get(&self) -> u32 {
self.a
}
}
impl B for Fee {
fn get(&self) -> String {
self.b.clone()
}
}
let fee = Fee {
a: 1234,
b: "asdf".to_string(),
};
let a = <Fee as A>::get(&fee);
let b = <Fee as B>::get(&fee);
println!("The a is {} and the b is {}", a, b);
}