mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-24 03:53:29 +00:00
319 lines
6.6 KiB
Markdown
319 lines
6.6 KiB
Markdown
|
# Rust Basics
|
|||
|
|
|||
|
### Generic Types
|
|||
|
|
|||
|
Create a struct where 1 of their values could be any type
|
|||
|
|
|||
|
```rust
|
|||
|
struct Wrapper<T> {
|
|||
|
value: T,
|
|||
|
}
|
|||
|
|
|||
|
impl<T> Wrapper<T> {
|
|||
|
pub fn new(value: T) -> Self {
|
|||
|
Wrapper { value }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Wrapper::new(42).value
|
|||
|
Wrapper::new("Foo").value, "Foo"
|
|||
|
```
|
|||
|
|
|||
|
### Option, Some & None
|
|||
|
|
|||
|
The Option type means that the value might by of type Some (there is something) or None:
|
|||
|
|
|||
|
```rust
|
|||
|
pub enum Option<T> {
|
|||
|
None,
|
|||
|
Some(T),
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
You can use functions such as `is_some()` or `is_none()` to check the value of the Option.
|
|||
|
|
|||
|
### Macros
|
|||
|
|
|||
|
Macros are more powerful than functions because they expand to produce more code than the code you’ve written manually. For example, a function signature must declare the number and type of parameters the function has. Macros, on the other hand, can take a variable number of parameters: we can call `println!("hello")` with one argument or `println!("hello {}", name)` with two arguments. Also, macros are expanded before the compiler interprets the meaning of the code, so a macro can, for example, implement a trait on a given type. A function can’t, because it gets called at runtime and a trait needs to be implemented at compile time.
|
|||
|
|
|||
|
```rust
|
|||
|
macro_rules! my_macro {
|
|||
|
() => {
|
|||
|
println!("Check out my macro!");
|
|||
|
};
|
|||
|
($val:expr) => {
|
|||
|
println!("Look at this other macro: {}", $val);
|
|||
|
}
|
|||
|
}
|
|||
|
fn main() {
|
|||
|
my_macro!();
|
|||
|
my_macro!(7777);
|
|||
|
}
|
|||
|
|
|||
|
// Export a macro from a module
|
|||
|
mod macros {
|
|||
|
#[macro_export]
|
|||
|
macro_rules! my_macro {
|
|||
|
() => {
|
|||
|
println!("Check out my macro!");
|
|||
|
};
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### Iterate
|
|||
|
|
|||
|
```rust
|
|||
|
// Iterate through a vector
|
|||
|
let my_fav_fruits = vec!["banana", "raspberry"];
|
|||
|
let mut my_iterable_fav_fruits = my_fav_fruits.iter();
|
|||
|
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
|
|||
|
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
|
|||
|
assert_eq!(my_iterable_fav_fruits.next(), None); // When it's over, it's none
|
|||
|
|
|||
|
// One line iteration with action
|
|||
|
my_fav_fruits.iter().map(|x| capitalize_first(x)).collect()
|
|||
|
|
|||
|
// Hashmap iteration
|
|||
|
for (key, hashvalue) in &*map {
|
|||
|
for key in map.keys() {
|
|||
|
for value in map.values() {
|
|||
|
```
|
|||
|
|
|||
|
### Recursive Box
|
|||
|
|
|||
|
```rust
|
|||
|
enum List {
|
|||
|
Cons(i32, List),
|
|||
|
Nil,
|
|||
|
}
|
|||
|
|
|||
|
let list = Cons(1, Cons(2, Cons(3, Nil)));
|
|||
|
```
|
|||
|
|
|||
|
### Conditionals
|
|||
|
|
|||
|
#### if
|
|||
|
|
|||
|
```rust
|
|||
|
let n = 5;
|
|||
|
if n < 0 {
|
|||
|
print!("{} is negative", n);
|
|||
|
} else if n > 0 {
|
|||
|
print!("{} is positive", n);
|
|||
|
} else {
|
|||
|
print!("{} is zero", n);
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### match
|
|||
|
|
|||
|
```rust
|
|||
|
match number {
|
|||
|
// Match a single value
|
|||
|
1 => println!("One!"),
|
|||
|
// Match several values
|
|||
|
2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
|
|||
|
// TODO ^ Try adding 13 to the list of prime values
|
|||
|
// Match an inclusive range
|
|||
|
13..=19 => println!("A teen"),
|
|||
|
// Handle the rest of cases
|
|||
|
_ => println!("Ain't special"),
|
|||
|
}
|
|||
|
|
|||
|
let boolean = true;
|
|||
|
// Match is an expression too
|
|||
|
let binary = match boolean {
|
|||
|
// The arms of a match must cover all the possible values
|
|||
|
false => 0,
|
|||
|
true => 1,
|
|||
|
// TODO ^ Try commenting out one of these arms
|
|||
|
};
|
|||
|
```
|
|||
|
|
|||
|
#### loop (infinite)
|
|||
|
|
|||
|
```rust
|
|||
|
loop {
|
|||
|
count += 1;
|
|||
|
if count == 3 {
|
|||
|
println!("three");
|
|||
|
continue;
|
|||
|
}
|
|||
|
println!("{}", count);
|
|||
|
if count == 5 {
|
|||
|
println!("OK, that's enough");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### while
|
|||
|
|
|||
|
```rust
|
|||
|
let mut n = 1;
|
|||
|
while n < 101 {
|
|||
|
if n % 15 == 0 {
|
|||
|
println!("fizzbuzz");
|
|||
|
} else if n % 5 == 0 {
|
|||
|
println!("buzz");
|
|||
|
} else {
|
|||
|
println!("{}", n);
|
|||
|
}
|
|||
|
n += 1;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### for
|
|||
|
|
|||
|
```rust
|
|||
|
for n in 1..101 {
|
|||
|
if n % 15 == 0 {
|
|||
|
println!("fizzbuzz");
|
|||
|
} else {
|
|||
|
println!("{}", n);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Use "..=" to make inclusive both ends
|
|||
|
for n in 1..=100 {
|
|||
|
if n % 15 == 0 {
|
|||
|
println!("fizzbuzz");
|
|||
|
} else if n % 3 == 0 {
|
|||
|
println!("fizz");
|
|||
|
} else if n % 5 == 0 {
|
|||
|
println!("buzz");
|
|||
|
} else {
|
|||
|
println!("{}", n);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// ITERATIONS
|
|||
|
|
|||
|
let names = vec!["Bob", "Frank", "Ferris"];
|
|||
|
//iter - Doesn't consume the collection
|
|||
|
for name in names.iter() {
|
|||
|
match name {
|
|||
|
&"Ferris" => println!("There is a rustacean among us!"),
|
|||
|
_ => println!("Hello {}", name),
|
|||
|
}
|
|||
|
}
|
|||
|
//into_iter - COnsumes the collection
|
|||
|
for name in names.into_iter() {
|
|||
|
match name {
|
|||
|
"Ferris" => println!("There is a rustacean among us!"),
|
|||
|
_ => println!("Hello {}", name),
|
|||
|
}
|
|||
|
}
|
|||
|
//iter_mut - This mutably borrows each element of the collection
|
|||
|
for name in names.iter_mut() {
|
|||
|
*name = match name {
|
|||
|
&mut "Ferris" => "There is a rustacean among us!",
|
|||
|
_ => "Hello",
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### if let
|
|||
|
|
|||
|
```rust
|
|||
|
let optional_word = Some(String::from("rustlings"));
|
|||
|
if let word = optional_word {
|
|||
|
println!("The word is: {}", word);
|
|||
|
} else {
|
|||
|
println!("The optional word doesn't contain anything");
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### while let
|
|||
|
|
|||
|
```rust
|
|||
|
let mut optional = Some(0);
|
|||
|
// This reads: "while `let` destructures `optional` into
|
|||
|
// `Some(i)`, evaluate the block (`{}`). Else `break`.
|
|||
|
while let Some(i) = optional {
|
|||
|
if i > 9 {
|
|||
|
println!("Greater than 9, quit!");
|
|||
|
optional = None;
|
|||
|
} else {
|
|||
|
println!("`i` is `{:?}`. Try again.", i);
|
|||
|
optional = Some(i + 1);
|
|||
|
}
|
|||
|
// ^ Less rightward drift and doesn't require
|
|||
|
// explicitly handling the failing case.
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### Traits
|
|||
|
|
|||
|
Create a new method for a type
|
|||
|
|
|||
|
```rust
|
|||
|
trait AppendBar {
|
|||
|
fn append_bar(self) -> Self;
|
|||
|
}
|
|||
|
|
|||
|
impl AppendBar for String {
|
|||
|
fn append_bar(self) -> Self{
|
|||
|
format!("{}Bar", self)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
let s = String::from("Foo");
|
|||
|
let s = s.append_bar();
|
|||
|
println!("s: {}", s);
|
|||
|
```
|
|||
|
|
|||
|
### Tests
|
|||
|
|
|||
|
```rust
|
|||
|
#[cfg(test)]
|
|||
|
mod tests {
|
|||
|
#[test]
|
|||
|
fn you_can_assert() {
|
|||
|
assert!(true);
|
|||
|
assert_eq!(true, true);
|
|||
|
assert_ne!(true, false);
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### Threading
|
|||
|
|
|||
|
#### Arc
|
|||
|
|
|||
|
An Arc can use Clone to create more references over the object to pass them to the threads. When the last reference pointer to a value is out of scope, the variable is dropped.
|
|||
|
|
|||
|
```rust
|
|||
|
use std::sync::Arc;
|
|||
|
let apple = Arc::new("the same apple");
|
|||
|
for _ in 0..10 {
|
|||
|
let apple = Arc::clone(&apple);
|
|||
|
thread::spawn(move || {
|
|||
|
println!("{:?}", apple);
|
|||
|
});
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
#### Threads
|
|||
|
|
|||
|
In this case we will pass the thread a variable it will be able to modify
|
|||
|
|
|||
|
```rust
|
|||
|
fn main() {
|
|||
|
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
|
|||
|
let status_shared = Arc::clone(&status);
|
|||
|
thread::spawn(move || {
|
|||
|
for _ in 0..10 {
|
|||
|
thread::sleep(Duration::from_millis(250));
|
|||
|
let mut status = status_shared.lock().unwrap();
|
|||
|
status.jobs_completed += 1;
|
|||
|
}
|
|||
|
});
|
|||
|
while status.lock().unwrap().jobs_completed < 10 {
|
|||
|
println!("waiting... ");
|
|||
|
thread::sleep(Duration::from_millis(500));
|
|||
|
}
|
|||
|
}
|
|||
|
```
|