Compare commits
10 Commits
6ad0ec2fc9
...
1d2bfbac3f
| 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"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
default-run = "rust-by-example"
|
||||
|
||||
[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"),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
25
src/main.rs
25
src/main.rs
@@ -5,15 +5,11 @@
|
||||
// : /// 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 threads;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "./test/basic_test.rs"]
|
||||
mod test;
|
||||
|
||||
fn main() {
|
||||
// helloworld::hello_world_module();
|
||||
@@ -24,5 +20,14 @@ fn main() {
|
||||
//conversion::conversion_module();
|
||||
// controlflow::control_flow_module();
|
||||
// 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
|
||||
* */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user