Compare commits
10 Commits
6ad0ec2fc9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d2bfbac3f | |||
| 266bd1e125 | |||
| 47313f061e | |||
| 0962166a06 | |||
| 2318258718 | |||
| d5a66a151b | |||
| fc48949ad9 | |||
| 2213d38728 | |||
| a84316fd93 | |||
| d078910cbe |
1645
Cargo.lock
generated
1645
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -2,5 +2,11 @@
|
|||||||
name = "rust-by-example"
|
name = "rust-by-example"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
default-run = "rust-by-example"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rand = "0.9.2"
|
||||||
|
reqwest = "0.12.22"
|
||||||
|
# clap = "2.27.1" # from crates.io
|
||||||
|
# rand = { git = "https://github.com/rust-lang-nursery/rand" } # from online repo
|
||||||
|
# bar = { path = "../bar" } # from a path in the local filesystem
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
# Rust by example
|
# [Rust by example](https://doc.rust-lang.org/stable/rust-by-example/)
|
||||||
|
|||||||
4
src/bin/secondary_main.rs
Normal file
4
src/bin/secondary_main.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("This was ran with '$ cargo run --bin secondary_main'");
|
||||||
|
println!("This is a secondary main!");
|
||||||
|
}
|
||||||
14
src/concepts/box_basics.rs
Normal file
14
src/concepts/box_basics.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
fn box_integer(number: i32) -> Box<i32> {
|
||||||
|
Box::new(number)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_function() -> Box<fn(i32) -> Box<i32>> {
|
||||||
|
Box::new(box_integer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn box_basics() {
|
||||||
|
let boxed_int = box_integer(3);
|
||||||
|
let boxed_boxer = box_function();
|
||||||
|
let another_boxed_int = boxed_boxer(4);
|
||||||
|
print!("Box basics: {} {}", boxed_int, another_boxed_int);
|
||||||
|
}
|
||||||
3
src/concepts/mod.rs
Normal file
3
src/concepts/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
mod box_basics;
|
||||||
|
|
||||||
|
pub use box_basics::box_basics;
|
||||||
@@ -195,4 +195,45 @@ pub fn control_flow_module() {
|
|||||||
n @ 1..5 => println!("{n} is between 1 and 5"),
|
n @ 1..5 => println!("{n} is between 1 and 5"),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If let
|
||||||
|
// Lets you simplify destructuring
|
||||||
|
// Usefull if objecto neither implements nor derives PartialEq (cant do variable == Object::A)
|
||||||
|
if let n @ 1..5 = another_number {
|
||||||
|
println!("{n} is between 1 and 5");
|
||||||
|
}
|
||||||
|
|
||||||
|
// can also be used to match an enum
|
||||||
|
enum Fooo {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
Another(u32),
|
||||||
|
};
|
||||||
|
|
||||||
|
let a = Fooo::A;
|
||||||
|
let b = Fooo::Another(3);
|
||||||
|
|
||||||
|
if let Fooo::A = a {
|
||||||
|
println!("a is A");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Fooo::Another(n) = b {
|
||||||
|
println!("b is another({n})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let else
|
||||||
|
//<span class="underline"> Acts as a try - catch when delcaring variables
|
||||||
|
|
||||||
|
// while let
|
||||||
|
// Similar to if let, to make match sequences more tolerable
|
||||||
|
let mut optional = Some(0);
|
||||||
|
|
||||||
|
while let Some(i) = optional {
|
||||||
|
if i > 9 {
|
||||||
|
println!("Greater than 9");
|
||||||
|
optional = None;
|
||||||
|
} else {
|
||||||
|
optional = Some(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
65
src/exercises/easy_difficulty.rs
Normal file
65
src/exercises/easy_difficulty.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
pub fn binary_search<T>(list: &[T], value: T) -> Result<usize, &'static str>
|
||||||
|
where
|
||||||
|
T: PartialOrd + Clone,
|
||||||
|
{
|
||||||
|
if !is_sorted(list) {
|
||||||
|
return Err("Input list must be sorted");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut current_slice = list;
|
||||||
|
let mut original_index: Option<usize> = None;
|
||||||
|
while !current_slice.is_empty() {
|
||||||
|
let middle = current_slice.len() / 2;
|
||||||
|
|
||||||
|
if current_slice[middle] == value {
|
||||||
|
let result = match original_index {
|
||||||
|
Some(i) => i + middle,
|
||||||
|
None => middle,
|
||||||
|
};
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
if middle < 1 {
|
||||||
|
return Err("Not found");
|
||||||
|
}
|
||||||
|
if current_slice[middle] > value {
|
||||||
|
current_slice = current_slice.split_at(middle).0;
|
||||||
|
} else {
|
||||||
|
current_slice = current_slice.split_at(middle).1;
|
||||||
|
if original_index.is_none() {
|
||||||
|
original_index = Some(middle);
|
||||||
|
} else {
|
||||||
|
original_index = Some(original_index.unwrap() + middle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err("Not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_sorted<T>(list: &[T]) -> bool
|
||||||
|
where
|
||||||
|
T: PartialOrd,
|
||||||
|
{
|
||||||
|
for index in 1..list.len() {
|
||||||
|
if list[index] < list[index - 1] {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: read about good practices when using mutable parameters
|
||||||
|
// maybe the correct thing to do is to take an immutable one and create a copy inside the function.
|
||||||
|
pub fn bubble_sort<T>(mut list: Vec<T>) -> Vec<T>
|
||||||
|
where
|
||||||
|
T: PartialOrd,
|
||||||
|
{
|
||||||
|
for lap in 1..list.len() {
|
||||||
|
for index in (lap..list.len()).rev() {
|
||||||
|
if list[index] < list[index - 1] {
|
||||||
|
list.swap(index, index - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list
|
||||||
|
}
|
||||||
66
src/exercises/hard_difficulty.rs
Normal file
66
src/exercises/hard_difficulty.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
Exercise: Implement a Multithreaded Web Crawler
|
||||||
|
|
||||||
|
#### Objective:
|
||||||
|
Create a simple multithreaded web crawler in Rust that can visit a set of web pages concurrently and extract all the links from those pages.
|
||||||
|
|
||||||
|
#### Requirements:
|
||||||
|
1. **Concurrent Fetching:** The crawler should utilize multiple threads to fetch web pages to improve performance.
|
||||||
|
2. **Link Extraction:** For each page visited by the crawler, extract all the hyperlinks (`<a href="...">`) present on the page.
|
||||||
|
3. **Avoid Cycles:** Ensure the crawler doesn't visit the same page more than once.
|
||||||
|
4. **Limit Depth:** Allow the user to specify the maximum depth for crawling (i.e., the maximum number of links to follow from the initial set of given URLs).
|
||||||
|
5. **Graceful Shutdown:** Allow the crawler to be stopped gracefully upon receiving a user interrupt (like pressing Ctrl+C).
|
||||||
|
|
||||||
|
#### Steps to Implement:
|
||||||
|
1. **Set Up the Project:**
|
||||||
|
- Create a new Rust project using Cargo.
|
||||||
|
|
||||||
|
2. **Implement URL Fetching:**
|
||||||
|
- Use `reqwest` or a similar library to fetch the contents of a web page.
|
||||||
|
- Handle networking errors gracefully.
|
||||||
|
|
||||||
|
3. **Extract Links:**
|
||||||
|
- Use the `scraper` crate or implement your own HTML parsing logic to extract links from the fetched HTML content.
|
||||||
|
|
||||||
|
4. **Multithreading:**
|
||||||
|
- Utilize Rust's `std::thread` or the `tokio` runtime to spawn threads that can concurrently fetch and process web pages.
|
||||||
|
|
||||||
|
5. **Avoid Revisits:**
|
||||||
|
- Maintain a `HashSet` or similar structure to keep track of visited URLs to prevent revisiting the same page.
|
||||||
|
|
||||||
|
6. **Depth Control:**
|
||||||
|
- Use a data structure (like a queue) to manage the list of URLs to visit, and keep track of the current depth level for each URL.
|
||||||
|
|
||||||
|
7. **Graceful Shutdown:**
|
||||||
|
- Implement signal handling to catch user interrupts and terminate the crawling process gracefully.
|
||||||
|
|
||||||
|
8. **Testing:**
|
||||||
|
- Write tests to ensure the crawler functions as expected, including edge cases like broken links, non-responsive pages, etc.
|
||||||
|
|
||||||
|
#### Hints:
|
||||||
|
- Consider using Rust's ownership model to manage shared state across threads safely.
|
||||||
|
- Make use of concurrency primitives like `Arc` and `Mutex` to safely share data between threads.
|
||||||
|
- Efficiently manage the queue of URLs to visit, making sure to handle potential deadlocks and race conditions.
|
||||||
|
|
||||||
|
This exercise will test the candidate's ability to work with network requests, concurrency, and data structures in Rust, while also evaluating their understanding of graceful error handling and software design.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #[derive(Debug)]
|
||||||
|
// struct HyperLink<'a> {
|
||||||
|
// href: &'a str,
|
||||||
|
// label: &'a str,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// struct PageData<'a> {
|
||||||
|
// links: Vec<HyperLink<'a>>,
|
||||||
|
// url: &'a str,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn web_crawler(url_list: Vec<&str>) -> Vec<PageData> {}
|
||||||
|
|
||||||
|
// fn get_page_links(url: &str) -> PageData {
|
||||||
|
// PageData { links: (), url }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn get_page_body(url: &str) -> &str {}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
pub fn longest_palindrome(value: &str) -> String {
|
|
||||||
let mut lp: String = "0".to_string();
|
|
||||||
let input_size = value.len() - 1;
|
|
||||||
|
|
||||||
for pal_size in 2..=input_size {
|
|
||||||
for i in 0..input_size {
|
|
||||||
if input_size - i < pal_size {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if let Some(slice) = value.get(i..(i + pal_size - 1)) {
|
|
||||||
// let reverted_slice = slice.chars().rev().collect::<String>();
|
|
||||||
// if string was mutable, we count use .reserve()
|
|
||||||
let reverted_slice = slice.chars().rev().collect::<String>();
|
|
||||||
if slice == reverted_slice {
|
|
||||||
lp = reverted_slice;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lp
|
|
||||||
}
|
|
||||||
101
src/exercises/medium_difficulty.rs
Normal file
101
src/exercises/medium_difficulty.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Count squares
|
||||||
|
*/
|
||||||
|
pub fn count_squares(matrix: &Vec<Vec<bool>>) -> usize {
|
||||||
|
let mut square_count: usize = 0;
|
||||||
|
|
||||||
|
for j in 0..matrix.len() {
|
||||||
|
for i in 0..matrix[0].len() {
|
||||||
|
if matrix[i][j] == true {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
square_count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn does_matrix_square_at(matrix: &Vec<Vec<bool>>) -> bool {}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mirror number
|
||||||
|
*/
|
||||||
|
pub fn mirror_number(mut value: u32) -> u32 {
|
||||||
|
const BASE: u32 = 10;
|
||||||
|
|
||||||
|
let mut mirror: u32 = 0;
|
||||||
|
let size = value.to_string().len();
|
||||||
|
|
||||||
|
for index in 1..=size {
|
||||||
|
let last = value % BASE;
|
||||||
|
value = value / BASE;
|
||||||
|
mirror += last * BASE.pow(size as u32 - index as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
mirror
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mirror_number_lazy(value: u32) -> u32 {
|
||||||
|
value
|
||||||
|
.to_string()
|
||||||
|
.chars()
|
||||||
|
.rev()
|
||||||
|
.collect::<String>()
|
||||||
|
.parse::<u32>()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn longest_palindrome(value: &str) -> String {
|
||||||
|
let mut lp: String = "0".to_string();
|
||||||
|
let input_size = value.len() - 1;
|
||||||
|
|
||||||
|
for pal_size in 2..=input_size {
|
||||||
|
for i in 0..input_size {
|
||||||
|
if input_size - i < pal_size {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(slice) = value.get(i..(i + pal_size - 1)) {
|
||||||
|
// if string was mutable, we count use .reserve()
|
||||||
|
let reverted_slice = slice.chars().rev().collect::<String>();
|
||||||
|
if slice == reverted_slice {
|
||||||
|
lp = reverted_slice;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lp
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Quick sort
|
||||||
|
*/
|
||||||
|
pub fn quick_sort<T>(list: Vec<T>) -> Vec<T>
|
||||||
|
where
|
||||||
|
T: PartialOrd + Copy,
|
||||||
|
{
|
||||||
|
if list.is_empty() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
let mut pivot_list = vec![list[0]];
|
||||||
|
let pivot = pivot_list[0];
|
||||||
|
// arrange
|
||||||
|
let mut left_list: Vec<T> = Vec::new();
|
||||||
|
let mut right_list: Vec<T> = Vec::new();
|
||||||
|
for index in 1..list.len() {
|
||||||
|
let element = list[index];
|
||||||
|
if element > pivot {
|
||||||
|
right_list.push(element);
|
||||||
|
} else if element < pivot {
|
||||||
|
left_list.push(element);
|
||||||
|
} else {
|
||||||
|
pivot_list.push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
left_list = quick_sort(left_list);
|
||||||
|
right_list = quick_sort(right_list);
|
||||||
|
left_list.append(&mut pivot_list);
|
||||||
|
left_list.append(&mut right_list);
|
||||||
|
|
||||||
|
left_list
|
||||||
|
}
|
||||||
77
src/exercises/mod.rs
Normal file
77
src/exercises/mod.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
mod easy_difficulty;
|
||||||
|
mod hard_difficulty;
|
||||||
|
mod medium_difficulty;
|
||||||
|
|
||||||
|
pub fn run_hard() {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_medium() {
|
||||||
|
println!(
|
||||||
|
"Longest palindrome of 'asdffdas' is {}",
|
||||||
|
medium_difficulty::longest_palindrome("asdffdas")
|
||||||
|
);
|
||||||
|
|
||||||
|
let to_mirror = 12345u32;
|
||||||
|
|
||||||
|
let begin = Instant::now();
|
||||||
|
println!(
|
||||||
|
"The mirror of {} is {} and took {:?}",
|
||||||
|
to_mirror,
|
||||||
|
medium_difficulty::mirror_number(to_mirror),
|
||||||
|
begin.elapsed()
|
||||||
|
);
|
||||||
|
|
||||||
|
let begin = Instant::now();
|
||||||
|
println!(
|
||||||
|
"(lazy) The mirror of {} is {} and took {:?}",
|
||||||
|
to_mirror,
|
||||||
|
medium_difficulty::mirror_number_lazy(to_mirror),
|
||||||
|
begin.elapsed()
|
||||||
|
);
|
||||||
|
|
||||||
|
let boolean_matrix = vec![
|
||||||
|
vec![true, false, true, true],
|
||||||
|
vec![false, false, true, true],
|
||||||
|
];
|
||||||
|
println!(
|
||||||
|
"The matrix:\n{:?}\nhas {} squares inside",
|
||||||
|
boolean_matrix,
|
||||||
|
medium_difficulty::count_squares(&boolean_matrix)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_easy() {
|
||||||
|
let list = vec![5, 1, 8, 20, 4];
|
||||||
|
// easy_difficulty::binary_search(list, 20);
|
||||||
|
// let list = easy_difficulty::slow_sort_list(list);
|
||||||
|
// println!("List ordered to {:?}", list);
|
||||||
|
println!(
|
||||||
|
"The vec {:?} is {} sorted, but [1,2,3,4] is {} sorted",
|
||||||
|
list,
|
||||||
|
easy_difficulty::is_sorted(&list),
|
||||||
|
easy_difficulty::is_sorted(&[1, 2, 3, 4])
|
||||||
|
);
|
||||||
|
|
||||||
|
let sorted_list = vec![1, 10, 15, 20, 30];
|
||||||
|
let searched = 40;
|
||||||
|
let position = easy_difficulty::binary_search(&sorted_list, searched);
|
||||||
|
match position {
|
||||||
|
Ok(pos) => println!(
|
||||||
|
"The element {searched} is indexed in {pos} at {:?}",
|
||||||
|
sorted_list
|
||||||
|
),
|
||||||
|
Err(e) => println!("Error: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
let bubled_list = easy_difficulty::bubble_sort(list);
|
||||||
|
println!("The original list sorted is {:?}", bubled_list);
|
||||||
|
|
||||||
|
let long_list = vec![
|
||||||
|
5, 1, 8, 20, 4, 15, 6, 7, 1, 4, 23, 9, 23, 5, 7, 7, 8, 0, 12, 4, 56, 18, 47, 23,
|
||||||
|
];
|
||||||
|
let sorted_list = medium_difficulty::quick_sort(long_list);
|
||||||
|
println!("The sorted list is: {:?}", sorted_list);
|
||||||
|
}
|
||||||
117
src/functions.rs
Normal file
117
src/functions.rs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
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: 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();
|
||||||
|
}
|
||||||
BIN
src/lib/libmy_lib.rlib
Normal file
BIN
src/lib/libmy_lib.rlib
Normal file
Binary file not shown.
103
src/macros.rs
Normal file
103
src/macros.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/main.rs
27
src/main.rs
@@ -5,15 +5,11 @@
|
|||||||
// : /// Doc comment: generate library docs for the following item
|
// : /// Doc comment: generate library docs for the following item
|
||||||
// : //! Doc comment
|
// : //! Doc comment
|
||||||
|
|
||||||
// mod helloworld;
|
mod threads;
|
||||||
// mod primitives;
|
|
||||||
// mod customtypes;
|
#[cfg(test)]
|
||||||
//mod variablebindings;
|
#[path = "./test/basic_test.rs"]
|
||||||
// mod types;
|
mod test;
|
||||||
//mod conversion;
|
|
||||||
// mod controlflow;
|
|
||||||
// mod traits;
|
|
||||||
mod str_types;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// helloworld::hello_world_module();
|
// helloworld::hello_world_module();
|
||||||
@@ -23,6 +19,15 @@ fn main() {
|
|||||||
//types::types_module();
|
//types::types_module();
|
||||||
//conversion::conversion_module();
|
//conversion::conversion_module();
|
||||||
// controlflow::control_flow_module();
|
// controlflow::control_flow_module();
|
||||||
//traits::traits_exercise();
|
// traits::traits_exercise();
|
||||||
str_types::str_types_module();
|
// str_types::str_types_module();
|
||||||
|
// my_lib::public_function();
|
||||||
|
// functions::functions_module();
|
||||||
|
// concepts::box_basics();
|
||||||
|
// operators::operators_module();
|
||||||
|
// macros_rule();
|
||||||
|
|
||||||
|
// exercises::run_easy();
|
||||||
|
// exercises::run_medium();
|
||||||
|
threads::threads_module();
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/my_lib.rs
Normal file
8
src/my_lib.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
pub fn public_function() {
|
||||||
|
println!("This is a public funcion that calls a private one!");
|
||||||
|
private_function();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_function() {
|
||||||
|
println!("This is a private function!");
|
||||||
|
}
|
||||||
24
src/operators.rs
Normal file
24
src/operators.rs
Normal 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
|
||||||
|
}
|
||||||
14
src/test/basic_test.rs
Normal file
14
src/test/basic_test.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
#[test]
|
||||||
|
fn test_success() {
|
||||||
|
let my_hello = "Hello world!";
|
||||||
|
assert_eq!(my_hello, "Hello world!");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_failure() {
|
||||||
|
let my_hello = "ef u world!";
|
||||||
|
assert_eq!(my_hello, "Hello world!");
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/threads.rs
Normal file
68
src/threads.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use std::{thread, time::Instant};
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
const NTHREADS: u32 = 6;
|
||||||
|
|
||||||
|
fn generate_number_block(size: usize) -> String {
|
||||||
|
let mut block = String::new();
|
||||||
|
for _ in 0..size {
|
||||||
|
block.push_str(&rand::rng().random_range(0..9).to_string());
|
||||||
|
}
|
||||||
|
block
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn threads_module() {
|
||||||
|
let number_block = generate_number_block(999999);
|
||||||
|
|
||||||
|
let time = Instant::now();
|
||||||
|
let result_base = sum_of_block(&number_block);
|
||||||
|
let elapsed_base = time.elapsed();
|
||||||
|
println!("Functional took {}", elapsed_base.as_micros());
|
||||||
|
|
||||||
|
let time = Instant::now();
|
||||||
|
let result_parallel = sum_of_block_parallel(&number_block, 10);
|
||||||
|
let elapsed_parallel = time.elapsed();
|
||||||
|
println!("Parallel took {}", elapsed_parallel.as_micros());
|
||||||
|
|
||||||
|
if result_base == result_parallel {
|
||||||
|
println!(
|
||||||
|
"The results are the same ({}) and the time difference is {}",
|
||||||
|
result_base,
|
||||||
|
elapsed_parallel.as_micros() - elapsed_base.as_micros()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
println!("One is wrong...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sum_of_block_parallel(digits: &str, nthreads: usize) -> u32 {
|
||||||
|
let digits = digits.split_at(digits.len() / 2);
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sum_of_block(digits: &str) -> u32 {
|
||||||
|
digits
|
||||||
|
.chars()
|
||||||
|
.into_iter()
|
||||||
|
.map(|character| character.to_digit(10).unwrap())
|
||||||
|
.sum::<u32>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn basic_thread_wait() {
|
||||||
|
let mut thread_list = vec![];
|
||||||
|
for i in 0..NTHREADS {
|
||||||
|
thread_list.push(thread::spawn(move || {
|
||||||
|
println!("this is the thread {}", i);
|
||||||
|
return 1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for th in thread_list {
|
||||||
|
let result = th.join();
|
||||||
|
match result {
|
||||||
|
Ok(r) => println!("Thread finished! {:?}", r),
|
||||||
|
Err(e) => println!("Thread error {:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
* 4. Extend the trait with a second function and see what happens
|
* 4. Extend the trait with a second function and see what happens
|
||||||
* */
|
* */
|
||||||
|
|
||||||
|
use std::thread::current;
|
||||||
|
|
||||||
pub trait Move {
|
pub trait Move {
|
||||||
fn to(&mut self, x: i32, y: i32);
|
fn to(&mut self, x: i32, y: i32);
|
||||||
}
|
}
|
||||||
@@ -32,4 +34,91 @@ pub fn traits_exercise() {
|
|||||||
me.to(10, 20);
|
me.to(10, 20);
|
||||||
|
|
||||||
println!("My name is {} and i'm at {:?}", me.name, me.position);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user