hacktricks/todo/rust-basics.md

449 lines
18 KiB
Markdown
Raw Normal View History

2024-02-10 22:40:18 +00:00
# Βασικά της Rust
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
### Γενικοί Τύποι
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
Δημιουργήστε ένα struct όπου μία από τις τιμές του μπορεί να είναι οποιοσδήποτε τύπος
2022-06-26 16:12:47 +00:00
```rust
struct Wrapper<T> {
2024-02-10 22:40:18 +00:00
value: T,
2022-06-26 16:12:47 +00:00
}
impl<T> Wrapper<T> {
2024-02-10 22:40:18 +00:00
pub fn new(value: T) -> Self {
Wrapper { value }
}
2022-06-26 16:12:47 +00:00
}
Wrapper::new(42).value
Wrapper::new("Foo").value, "Foo"
```
### Option, Some & None
2024-02-10 22:40:18 +00:00
Ο τύπος Option σημαίνει ότι η τιμή μπορεί να είναι τύπου Some (υπάρχει κάτι) ή None:
2022-06-26 16:12:47 +00:00
```rust
pub enum Option<T> {
2024-02-10 22:40:18 +00:00
None,
Some(T),
2022-06-26 16:12:47 +00:00
}
```
2024-02-10 22:40:18 +00:00
Μπορείτε να χρησιμοποιήσετε συναρτήσεις όπως `is_some()` ή `is_none()` για να ελέγξετε την τιμή της Option.
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
### Μακροεντολές
2022-06-27 08:23:29 +00:00
2024-02-10 22:40:18 +00:00
Οι μακροεντολές είναι πιο ισχυρές από τις συναρτήσεις επειδή διευρύνονται για να παράγουν περισσότερο κώδικα από αυτόν που έχετε γράψει χειροκίνητα. Για παράδειγμα, η υπογραφή μιας συνάρτησης πρέπει να δηλώσει τον αριθμό και τον τύπο των παραμέτρων που έχει η συνάρτηση. Οι μακροεντολές, από την άλλη πλευρά, μπορούν να πάρουν μεταβλητό αριθμό παραμέτρων: μπορούμε να καλέσουμε την `println!("hello")` με ένα όρισμα ή την `println!("hello {}", name)` με δύο ορίσματα. Επίσης, οι μακροεντολές διευρύνονται πριν ο μεταγλωττιστής ερμηνεύσει τη σημασία του κώδικα, έτσι μια μακροεντολή μπορεί, για παράδειγμα, να υλοποιήσει ένα trait σε έναν συγκεκριμένο τύπο. Μια συνάρτηση δεν μπορεί, επειδή καλείται κατά την εκτέλεση και ένα trait πρέπει να υλοποιηθεί κατά τη μεταγλώττιση.
2022-06-27 08:23:29 +00:00
```rust
macro_rules! my_macro {
2024-02-10 22:40:18 +00:00
() => {
println!("Check out my macro!");
};
($val:expr) => {
println!("Look at this other macro: {}", $val);
}
2022-06-27 08:23:29 +00:00
}
fn main() {
2024-02-10 22:40:18 +00:00
my_macro!();
my_macro!(7777);
2022-06-27 08:23:29 +00:00
}
// Export a macro from a module
mod macros {
2024-02-10 22:40:18 +00:00
#[macro_export]
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
}
```
### Επανάληψη
Η επανάληψη είναι μια σημαντική έννοια στην προγραμματισμό. Σας επιτρέπει να εκτελέσετε ένα σύνολο εντολών επαναλαμβανόμενα, μέχρι να ικανοποιηθεί μια συγκεκριμένη συνθήκη. Στη γλώσσα προγραμματισμού Rust, υπάρχουν διάφοροι τρόποι για να επαναλάβετε κώδικα, ανάλογα με τις ανάγκες σας.
#### Επανάληψη με τη χρήση της `loop`
Η εντολή `loop` εκτελεί μια σειρά εντολών επαναλαμβανόμενα για αόριστο χρονικό διάστημα. Για να διακόψετε την επανάληψη, μπορείτε να χρησιμοποιήσετε την εντολή `break` όταν μια συγκεκριμένη συνθήκη ικανοποιηθεί.
```rust
loop {
// Κώδικας που θα εκτελείται επαναλαμβανόμενα
if condition {
break;
2022-06-27 08:23:29 +00:00
}
}
```
2024-02-10 22:40:18 +00:00
#### Επανάληψη με τη χρήση της `while`
Η εντολή `while` εκτελεί μια σειρά εντολών επαναλαμβανόμενα όσο μια συγκεκριμένη συνθήκη είναι αληθής.
2022-06-27 08:23:29 +00:00
2024-02-10 22:40:18 +00:00
```rust
while condition {
// Κώδικας που θα εκτελείται επαναλαμβανόμενα
}
```
#### Επανάληψη με τη χρήση της `for`
Η εντολή `for` εκτελεί μια σειρά εντολών επαναλαμβανόμενα για κάθε στοιχείο μιας συλλογής, όπως ένας πίνακας ή ένας διάνυσμα.
```rust
for element in collection {
// Κώδικας που θα εκτελείται επαναλαμβανόμενα για κάθε στοιχείο
}
```
Αυτοί είναι οι βασικοί τρόποι επανάληψης στη γλώσσα προγραμματισμού Rust. Επιλέξτε τον κατάλληλο τρόπο επανάληψης ανάλογα με τις ανάγκες του προγράμματός σας.
2022-06-27 08:23:29 +00:00
```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
2024-02-10 22:40:18 +00:00
2022-06-27 08:23:29 +00:00
// 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() {
```
2024-02-10 22:40:18 +00:00
### Αναδρομικό Κουτί
Το αναδρομικό κουτί είναι ένα χρήσιμο εργαλείο στη γλώσσα προγραμματισμού Rust που μας επιτρέπει να αναφερόμαστε σε μια τιμή που αναφέρεται στον εαυτό της. Αυτό μας επιτρέπει να δημιουργούμε δομές δεδομένων που περιέχουν αναφορές στον εαυτό τους, δημιουργώντας έτσι αναδρομικές δομές.
2022-06-27 08:23:29 +00:00
2024-02-10 22:40:18 +00:00
Για να δημιουργήσουμε ένα αναδρομικό κουτί στη Rust, χρησιμοποιούμε τον τύπο δεδομένων `Box`. Ο τύπος `Box` είναι ένας έξυπνος δείκτης που αναλαμβάνει την αποδέσμευση της μνήμης όταν δεν χρειάζεται πλέον.
Για παράδειγμα, μπορούμε να δημιουργήσουμε ένα αναδρομικό κουτί που περιέχει έναν ακέραιο αριθμό ως εξής:
2022-06-27 08:23:29 +00:00
2024-02-10 22:40:18 +00:00
```rust
fn main() {
let recursive_box: Box<i32> = Box::new(42);
println!("Value: {}", recursive_box);
}
```
Στο παραπάνω παράδειγμα, δημιουργούμε ένα αναδρομικό κουτί με την τιμή 42 και το εκτυπώνουμε. Η μνήμη που καταλαμβάνει το αναδρομικό κουτί απελευθερώνεται αυτόματα όταν δεν υπάρχουν πλέον αναφορές σε αυτό.
Το αναδρομικό κουτί είναι ένα ισχυρό εργαλείο που μας επιτρέπει να δημιουργούμε πολύπλοκες δομές δεδομένων και αλγορίθμους στη Rust. Χρησιμοποιήστε το με προσοχή και κατανόηση των αναγκών σας για να αποφύγετε προβλήματα με τη μνήμη.
2022-06-27 08:23:29 +00:00
```rust
enum List {
2024-02-10 22:40:18 +00:00
Cons(i32, List),
Nil,
2022-06-27 08:23:29 +00:00
}
let list = Cons(1, Cons(2, Cons(3, Nil)));
```
2024-02-10 22:40:18 +00:00
### Συνθήκες
2022-06-26 16:12:47 +00:00
#### if
2024-02-10 22:40:18 +00:00
Η δομή ελέγχου `if` χρησιμοποιείται για να εκτελέσει ένα τμήμα κώδικα μόνο αν μια συγκεκριμένη συνθήκη είναι αληθής. Η σύνταξη της δομής `if` είναι η εξής:
```rust
if condition {
// Κώδικας που εκτελείται αν η συνθήκη είναι αληθής
}
```
Μπορείτε επίσης να προσθέσετε μια δομή `else` για να εκτελέσετε έναν διαφορετικό κώδικα αν η συνθήκη είναι ψευδής:
```rust
if condition {
// Κώδικας που εκτελείται αν η συνθήκη είναι αληθής
} else {
// Κώδικας που εκτελείται αν η συνθήκη είναι ψευδής
}
```
Μπορείτε επίσης να χρησιμοποιήσετε τη δομή `else if` για να ελέγξετε περισσότερες από μία συνθήκες:
```rust
if condition1 {
// Κώδικας που εκτελείται αν η συνθήκη 1 είναι αληθής
} else if condition2 {
// Κώδικας που εκτελείται αν η συνθήκη 2 είναι αληθής
} else {
// Κώδικας που εκτελείται αν καμία από τις προηγούμενες συνθήκες δεν είναι αληθής
}
```
2022-06-26 16:12:47 +00:00
```rust
let n = 5;
if n < 0 {
2024-02-10 22:40:18 +00:00
print!("{} is negative", n);
2022-06-26 16:12:47 +00:00
} else if n > 0 {
2024-02-10 22:40:18 +00:00
print!("{} is positive", n);
2022-06-26 16:12:47 +00:00
} else {
2024-02-10 22:40:18 +00:00
print!("{} is zero", n);
2022-06-26 16:12:47 +00:00
}
```
2024-02-10 22:40:18 +00:00
#### αντιστοίχιση
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
The `match` expression in Rust is used to compare a value against a series of patterns and execute the corresponding code block for the first matching pattern. It is similar to a switch statement in other programming languages.
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
```rust
match value {
pattern1 => {
// code block to execute if value matches pattern1
},
pattern2 => {
// code block to execute if value matches pattern2
},
// more patterns...
_ => {
// code block to execute if value does not match any pattern
}
}
```
The `_` pattern is a catch-all pattern that matches any value. It is commonly used as the last pattern to handle all remaining cases.
The `match` expression is powerful and flexible, allowing for complex pattern matching and exhaustive handling of all possible cases. It is often used in Rust to replace lengthy if-else chains and improve code readability.
2022-06-26 16:12:47 +00:00
```rust
match number {
2024-02-10 22:40:18 +00:00
// 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"),
2022-06-26 16:12:47 +00:00
}
let boolean = true;
// Match is an expression too
let binary = match boolean {
2024-02-10 22:40:18 +00:00
// The arms of a match must cover all the possible values
false => 0,
true => 1,
// TODO ^ Try commenting out one of these arms
2022-06-26 16:12:47 +00:00
};
```
2024-02-10 22:40:18 +00:00
#### βρόχος (άπειρος)
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
Ο βρόχος (loop) είναι μια δομή προγραμματισμού που επαναλαμβάνει μια συγκεκριμένη ενέργεια για έναν αόριστο αριθμό φορών. Αυτό σημαίνει ότι η ενέργεια θα εκτελείται συνεχώς μέχρι να δοθεί μια εντολή για να σταματήσει. Ο άπειρος βρόχος είναι ένας τύπος βρόχου που δεν έχει καμία συνθήκη για να τερματίσει και εκτελείται για πάντα, εκτός αν διακοπεί από τον χρήστη ή από κάποιο σφάλμα στο πρόγραμμα.
2022-06-26 16:12:47 +00:00
```rust
loop {
2024-02-10 22:40:18 +00:00
count += 1;
if count == 3 {
println!("three");
continue;
}
println!("{}", count);
if count == 5 {
println!("OK, that's enough");
break;
}
2022-06-26 16:12:47 +00:00
}
```
2024-02-10 22:40:18 +00:00
#### ενώ
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
The `while` statement in Rust is used to create a loop that will continue executing as long as a certain condition is true. The syntax for the `while` statement is as follows:
2022-06-26 16:12:47 +00:00
```rust
2024-02-10 22:40:18 +00:00
while condition {
// code to be executed
2022-06-26 16:12:47 +00:00
}
```
2024-02-10 22:40:18 +00:00
The `condition` is a boolean expression that determines whether the loop should continue or not. If the condition is true, the code inside the loop will be executed. Once the code is executed, the condition will be checked again. If the condition is still true, the code will be executed again, and this process will continue until the condition becomes false.
Here is an example of how the `while` statement can be used in Rust:
```rust
let mut count = 0;
while count < 5 {
println!("Count: {}", count);
count += 1;
}
```
2022-06-26 16:12:47 +00:00
2024-02-10 22:40:18 +00:00
In this example, the loop will continue executing as long as the value of `count` is less than 5. The value of `count` will be printed to the console, and then incremented by 1. This process will repeat until `count` reaches 5, at which point the condition will become false and the loop will terminate.
```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;
}
```
#### για
2022-06-26 16:12:47 +00:00
```rust
for n in 1..101 {
2024-02-10 22:40:18 +00:00
if n % 15 == 0 {
println!("fizzbuzz");
} else {
println!("{}", n);
}
2022-06-26 16:12:47 +00:00
}
// Use "..=" to make inclusive both ends
for n in 1..=100 {
2024-02-10 22:40:18 +00:00
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
2022-06-26 16:12:47 +00:00
}
// ITERATIONS
let names = vec!["Bob", "Frank", "Ferris"];
//iter - Doesn't consume the collection
for name in names.iter() {
2024-02-10 22:40:18 +00:00
match name {
&"Ferris" => println!("There is a rustacean among us!"),
_ => println!("Hello {}", name),
}
2022-06-26 16:12:47 +00:00
}
//into_iter - COnsumes the collection
for name in names.into_iter() {
2024-02-10 22:40:18 +00:00
match name {
"Ferris" => println!("There is a rustacean among us!"),
_ => println!("Hello {}", name),
}
2022-06-26 16:12:47 +00:00
}
//iter_mut - This mutably borrows each element of the collection
for name in names.iter_mut() {
2024-02-10 22:40:18 +00:00
*name = match name {
&mut "Ferris" => "There is a rustacean among us!",
_ => "Hello",
}
2022-06-26 16:12:47 +00:00
}
```
#### if let
2024-02-10 22:40:18 +00:00
Η δομή `if let` στη Rust είναι μια συντομευμένη μορφή της `match` που χρησιμοποιείται για να ελέγξει αν μια τιμή ταιριάζει με ένα συγκεκριμένο πρότυπο και να εκτελέσει κώδικα μόνο αν η ταιριάσουσα τιμή αντιστοιχεί στο πρότυπο. Αυτό είναι χρήσιμο όταν ενδιαφερόμαστε μόνο για ένα συγκεκριμένο πρότυπο και δεν μας ενδιαφέρει να καλύψουμε όλες τις πιθανές περιπτώσεις.
Η σύνταξη της `if let` είναι η εξής:
```rust
if let Some(value) = optional_value {
// Κώδικας που εκτελείται αν η optional_value είναι Some(value)
} else {
// Κώδικας που εκτελείται αν η optional_value είναι None
}
```
Στο παραπάνω παράδειγμα, ο κώδικας εκτελείται μόνο αν η `optional_value` είναι `Some(value)`, δηλαδή αν η τιμή είναι μια αποθηκευμένη τιμή και όχι `None`. Αν η `optional_value` είναι `None`, τότε εκτελείται ο κώδικας που βρίσκεται μέσα στην `else` παράγραφο.
Η `if let` μπορεί να χρησιμοποιηθεί με οποιοδήποτε πρότυπο που ταιριάζει με τον τύπο της τιμής που ελέγχεται. Μπορεί επίσης να χρησιμοποιηθεί με πολλαπλά πρότυπα χρησιμοποιώντας τον τελεστή `|`.
2022-06-26 16:12:47 +00:00
```rust
let optional_word = Some(String::from("rustlings"));
if let word = optional_word {
2024-02-10 22:40:18 +00:00
println!("The word is: {}", word);
2022-06-26 16:12:47 +00:00
} else {
2024-02-10 22:40:18 +00:00
println!("The optional word doesn't contain anything");
2022-06-26 16:12:47 +00:00
}
```
#### while let
2024-02-10 22:40:18 +00:00
Ο όρος `while let` χρησιμοποιείται για να εκτελεί μια επανάληψη ενώ μια τιμή παραμένει μια συγκεκριμένη τιμή. Αυτό είναι χρήσιμο όταν θέλουμε να εξετάσουμε μια τιμή και να εκτελέσουμε κώδικα μόνο αν η τιμή αντιστοιχεί σε ένα συγκεκριμένο πρότυπο.
Η σύνταξη του `while let` είναι η εξής:
```rust
while let Some(pattern) = optional_value {
// Κώδικας που εκτελείται όταν η τιμή αντιστοιχεί στο πρότυπο
}
```
Στο παραπάνω παράδειγμα, ο κώδικας εκτελείται μόνο όταν η `optional_value` είναι `Some` και η τιμή της αντιστοιχεί στο `pattern`. Αν η `optional_value` είναι `None` ή η τιμή της δεν αντιστοιχεί στο `pattern`, η επανάληψη τερματίζεται.
Ο όρος `while let` μπορεί να χρησιμοποιηθεί με οποιοδήποτε τύπο δεδομένων που υποστηρίζει το πρότυπο που καθορίζεται.
2022-06-26 16:12:47 +00:00
```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 {
2024-02-10 22:40:18 +00:00
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.
2022-06-26 16:12:47 +00:00
}
```
### Traits
2024-02-10 22:40:18 +00:00
Δημιουργία μιας νέας μεθόδου για έναν τύπο
2022-06-26 16:12:47 +00:00
```rust
trait AppendBar {
2024-02-10 22:40:18 +00:00
fn append_bar(self) -> Self;
2022-06-26 16:12:47 +00:00
}
impl AppendBar for String {
2024-02-10 22:40:18 +00:00
fn append_bar(self) -> Self{
format!("{}Bar", self)
}
2022-06-26 16:12:47 +00:00
}
let s = String::from("Foo");
let s = s.append_bar();
println!("s: {}", s);
```
2024-02-10 22:40:18 +00:00
### Δοκιμές
2022-06-26 16:12:47 +00:00
```rust
#[cfg(test)]
mod tests {
2024-02-10 22:40:18 +00:00
#[test]
fn you_can_assert() {
assert!(true);
assert_eq!(true, true);
assert_ne!(true, false);
}
2022-06-27 08:23:29 +00:00
}
```
2024-02-10 22:40:18 +00:00
### Πολλαπλές Νήματα
2022-06-27 08:23:29 +00:00
#### Arc
2024-02-10 22:40:18 +00:00
Ένα Arc μπορεί να χρησιμοποιήσει την Clone για να δημιουργήσει περισσότερες αναφορές πάνω στο αντικείμενο για να τις περάσει στα νήματα. Όταν η τελευταία αναφορά προς μια τιμή είναι εκτός εμβέλειας, η μεταβλητή απορρίπτεται.
2022-06-27 08:23:29 +00:00
```rust
use std::sync::Arc;
let apple = Arc::new("the same apple");
for _ in 0..10 {
2024-02-10 22:40:18 +00:00
let apple = Arc::clone(&apple);
thread::spawn(move || {
println!("{:?}", apple);
});
2022-06-27 08:23:29 +00:00
}
```
2024-02-10 22:40:18 +00:00
#### Νήματα
2022-06-27 08:23:29 +00:00
2024-02-10 22:40:18 +00:00
Σε αυτήν την περίπτωση θα περάσουμε στο νήμα μια μεταβλητή που θα μπορεί να τροποποιήσει.
2022-06-27 08:23:29 +00:00
```rust
fn main() {
2024-02-10 22:40:18 +00:00
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));
}
2022-06-26 16:12:47 +00:00
}
```
2024-02-10 22:40:18 +00:00