2020-10-14 11:29:08 +03:00
|
|
|
|
---
|
|
|
|
|
language: Rust
|
|
|
|
|
contributors:
|
|
|
|
|
- ["P1start", "http://p1start.github.io/"]
|
|
|
|
|
- ["Dimitri Kokkonis", "https://github.com/kokkonisd"]
|
|
|
|
|
filename: learnrust-gr.rs
|
|
|
|
|
lang: el-gr
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
_[ΣτΜ.: οι όροι "χαμηλό/υψηλό επίπεδο" αναφέρονται στην εγγύτητα μιας γλώσσας προγραμματισμού ή γενικότερα ενός
|
|
|
|
|
στοιχείου στην "μηχανή", ή το υλικό του υπολογιστή. Για παράδειγμα, η φράση "η C είναι μια γλώσσα χαμηλού επιπέδου"
|
|
|
|
|
αναφέρεται στο γεγονός ότι η C επιτρέπει άμεση και λεπτομερή διαχείρηση μνήμης, και πιο άμεσο έλεγχο του επεξεργαστή·
|
|
|
|
|
σε καμία περίπτωση δεν σημαίνει ότι η C έχει λιγότερες δυνατότητες, και γενικότερα δεν φέρει αρνητική σημασία.]_
|
|
|
|
|
|
|
|
|
|
Η Rust είναι μια γλώσσα προγραμματισμού ανεπτυγμένη από την Mozilla Research.
|
|
|
|
|
Συνδυάζει τον έλεγχο της απόδοσης χαμηλού επιπέδου με διευκολύνσεις και ασφάλεια υψηλού επιπέδου.
|
|
|
|
|
|
|
|
|
|
Πετυχαίνει αυτούς τους στόχους χωρίς να χρειάζεται garbage collector ή runtime, το οποίο καθιστά δυνατή τη χρήση
|
|
|
|
|
βιβλιοθηκών της Rust ως αντικατάσταση της C.
|
|
|
|
|
|
|
|
|
|
Η έκδοση 0.1 (η πρώτη της Rust) δημοσιεύθηκε τον Ιανουάριο του 2012, και για τα επόμενα 3 χρόνια η ανάπτυξή της
|
|
|
|
|
εξελίχθηκε τόσο γρήγορα που, μέχρι πρότινος, προτείνονταν η χρήση μη-σταθερών εκδόσεων (nightly builds) αντί σταθερών
|
|
|
|
|
εκδόσεων.
|
|
|
|
|
|
|
|
|
|
Τις 15 Μαΐου 2015 δημοσιεύτηκε η εκδοχή 1.0 της Rust, με πλήρη εγγύηση συμβατότητας με προηγούμενες εκδοχές. Οι
|
|
|
|
|
μη-σταθερές εκδόσεις συνήθως περιλαμβάνουν γρηγορότερους χρόνους μεταγλώττισης και γενικότερες βελτιώσεις όσον αφορά
|
|
|
|
|
τον μεταγλωττιστή. Η μέθοδος [train release](https://www.plutora.com/blog/agile-release-train) χρησιμοποιείται, με
|
|
|
|
|
συστηματικές εκδόσεις να δημοσιεύονται κάθε έξι εβδομάδες. Η beta έκδοση της Rust 1.1 δημοσιεύθηκε ταυτοχρόνως με την
|
|
|
|
|
σταθερή έκδοση 1.0.
|
|
|
|
|
|
|
|
|
|
Αν και η Rust είναι μια γλώσσα σχετικά χαμηλού επιπέδου, ο σχεδιασμός της περιλαμβάνει κάποιες έννοιες που συναντώνται
|
|
|
|
|
συνχότερα σε γλώσσες υψηλού επιπέδου. Αυτό καθιστά την Rust γρήγορη και αποδοτική αλλά επίσης εύκολη και προσβάσιμη.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
// Αυτό είναι ένα σχόλιο. Τα σχόλια μίας γραμμής γράφονται έτσι...
|
|
|
|
|
// Και επεκτείνονται σε περισσότερες από μία γραμμές έτσι.
|
|
|
|
|
|
|
|
|
|
/// Τα σχόλια documentation γράφονται έτσι, και υποστηρίζουν markdown.
|
|
|
|
|
/// # Παράδειγμα
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// let five = 5
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
|
|
//////////////////////
|
|
|
|
|
// 1. Βασικές αρχές //
|
|
|
|
|
//////////////////////
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
// Συναρτήσεις
|
|
|
|
|
// `i32` είναι ο τύπος που αντιστοιχεί στους 32-bit signed ακέραιους
|
|
|
|
|
fn add2(x: i32, y: i32) -> i32 {
|
|
|
|
|
// Έμεσα εννοούμενη επιστροφή του αποτελέσματος, χωρίς semicolon (;)
|
|
|
|
|
x + y
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(unused_variables)]
|
|
|
|
|
#[allow(unused_assignments)]
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
// Συνάρτηση main
|
|
|
|
|
fn main() {
|
|
|
|
|
// Αριθμοί //
|
|
|
|
|
|
|
|
|
|
// Αμετάβλητη σύνδεση
|
|
|
|
|
let x: i32 = 1;
|
|
|
|
|
|
|
|
|
|
// Καταλήξεις integer/float
|
|
|
|
|
let y: i32 = 13i32;
|
|
|
|
|
let f: f64 = 1.3f64;
|
|
|
|
|
|
|
|
|
|
// Εξακρίβωση τύπου (type inference)
|
|
|
|
|
// Τις περισσότερες φορες ο μεταγλωττιστής της Rust μπορεί να εξακριβώσει τον τύπο μιας μεταβλητής, επομένως δεν
|
|
|
|
|
// χρειάζεται ο προγραμματιστής να τον δηλώνει ρητά.
|
|
|
|
|
// Σε αυτό το tutorial, οι τύποι δηλώνονται ρητά σε διάφορα σημεία, αλλά μόνο προκειμένου να είναι πιο ευανάγνωστος
|
|
|
|
|
// ο κώδικας. Ο μεταγλωττιστής μπορεί να το διαχειριστεί αυτόματα στις περισσότερες περιπτώσεις.
|
|
|
|
|
let implicit_x = 1;
|
|
|
|
|
let implicit_f = 1.3;
|
|
|
|
|
|
|
|
|
|
// Πράξεις
|
|
|
|
|
let sum = x + y + 13;
|
|
|
|
|
|
|
|
|
|
// Μη-αμετάβλητη αξία (με την έννοια ότι μπορεί να αλλάξει)
|
|
|
|
|
let mut mutable = 1;
|
|
|
|
|
mutable = 4;
|
|
|
|
|
mutable += 2;
|
|
|
|
|
|
|
|
|
|
// Αλφαριθμητικά //
|
|
|
|
|
|
|
|
|
|
// Σταθερά αλφαριθμητικά
|
|
|
|
|
let x: &str = "καλημέρα κόσμε!";
|
|
|
|
|
|
|
|
|
|
// Εκτύπωση αλφαριθμητικών
|
|
|
|
|
println!("{} {}", f, x); // 1.3 καλημέρα κόσμε!
|
|
|
|
|
|
|
|
|
|
// A `String` – a heap-allocated string
|
|
|
|
|
let s: String = "καλημέρα κόσμε".to_string();
|
|
|
|
|
|
|
|
|
|
// Ένα κομμάτι αλφαριθμητικού (string slice) – μια μη-μεταβλητή οπτική γωνία προς ένα άλλο αλφαριθμητικό
|
|
|
|
|
// Το αλφαριθμητικό μπορεί να είναι στατικό όπως τα σταθερά αλφαριθμητικά, ή να περιλαμβάνεται σε ένα άλλο,
|
|
|
|
|
// δυναμικό αντικείμενο (σε αυτή την περίπτωση τη μεταβλητή `s`)
|
|
|
|
|
let s_slice: &str = &s;
|
|
|
|
|
|
|
|
|
|
println!("{} {}", s, s_slice); // καλημέρα κόσμε καλημέρα κόσμε
|
|
|
|
|
|
|
|
|
|
// Διανύσματα/πίνακες //
|
|
|
|
|
|
|
|
|
|
// Πίνακας σταθερού μεγέθους
|
|
|
|
|
let four_ints: [i32; 4] = [1, 2, 3, 4];
|
|
|
|
|
|
|
|
|
|
// Δυναμικός πίνακας (διάνυσμα)
|
|
|
|
|
let mut vector: Vec<i32> = vec![1, 2, 3, 4];
|
|
|
|
|
vector.push(5);
|
|
|
|
|
|
|
|
|
|
// Ένα κομμάτι – μια μη-μεταβλητή οπτική γωνία προς ένα διάνυσμα ή πίνακα
|
|
|
|
|
// Είναι παρόμοιο με το κομμάτι αλφαριθμητικού που είδαμε προηγουμένως
|
|
|
|
|
let slice: &[i32] = &vector;
|
|
|
|
|
|
|
|
|
|
// Μπορούμε να χρησιμοποιήσουμε το `{:?}` για να εκτυπώσουμε κάτι σε στυλ debug
|
|
|
|
|
println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
|
|
|
|
|
|
|
|
|
|
// Tuples (πλειάδες) //
|
|
|
|
|
|
|
|
|
|
// Ένα tuple είναι μια σταθερού μεγέθους σειρά από αξίες (πιθανά διαφορετικού τύπου)
|
|
|
|
|
let x: (i32, &str, f64) = (1, "καλημέρα", 3.4);
|
|
|
|
|
|
|
|
|
|
// Μπορούμε να χρησιμοποιήσουμε το `let` και ένα tuple για να δώσουμε πολλές αξίες σε πολλές μεταβλητές ταυτόχρονα
|
|
|
|
|
// (destructuring `let`)
|
|
|
|
|
let (a, b, c) = x;
|
|
|
|
|
println!("{} {} {}", a, b, c); // 1 καλημέρα 3.4
|
|
|
|
|
|
|
|
|
|
// Μπορούμε επίσης να επιλέξουμε ένα συγκεκριμένο στοιχείο από ένα tuple
|
|
|
|
|
println!("{}", x.1); // καλημέρα
|
|
|
|
|
|
|
|
|
|
//////////////
|
|
|
|
|
// 2. Τύποι //
|
|
|
|
|
//////////////
|
|
|
|
|
|
|
|
|
|
// Δομή
|
|
|
|
|
struct Point {
|
|
|
|
|
x: i32,
|
|
|
|
|
y: i32,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let origin: Point = Point { x: 0, y: 0 };
|
|
|
|
|
|
|
|
|
|
// Μια δομή με ανώνυμα πεδία, ή αλλιώς μια `δομή tuple` (`tuple struct`)
|
|
|
|
|
struct Point2(i32, i32);
|
|
|
|
|
|
|
|
|
|
let origin2 = Point2(0, 0);
|
|
|
|
|
|
|
|
|
|
// Enum, όπως στην C
|
|
|
|
|
enum Direction {
|
|
|
|
|
Left,
|
|
|
|
|
Right,
|
|
|
|
|
Up,
|
|
|
|
|
Down,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let up = Direction::Up;
|
|
|
|
|
|
|
|
|
|
// Enum με πεδία
|
|
|
|
|
enum OptionalI32 {
|
|
|
|
|
AnI32(i32),
|
|
|
|
|
Nothing,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let two: OptionalI32 = OptionalI32::AnI32(2);
|
|
|
|
|
let nothing = OptionalI32::Nothing;
|
|
|
|
|
|
|
|
|
|
// Γενικότητα (genericity) //
|
|
|
|
|
|
|
|
|
|
struct Foo<T> { bar: T }
|
|
|
|
|
|
|
|
|
|
// Αυτό ορίζεται στην standard library ως `Option`
|
|
|
|
|
enum Optional<T> {
|
|
|
|
|
SomeVal(T),
|
|
|
|
|
NoVal,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Μέθοδοι //
|
|
|
|
|
|
|
|
|
|
impl<T> Foo<T> {
|
|
|
|
|
// Οι μέθοδοι παίρνουν πάντα μια ρητή παράμετρο `self`
|
|
|
|
|
fn bar(&self) -> &T { // Δανειζόμαστε το self
|
|
|
|
|
&self.bar
|
|
|
|
|
}
|
|
|
|
|
fn bar_mut(&mut self) -> &mut T { // Δανειζόμαστε το self ως μη-αμετάβλητη αξία
|
|
|
|
|
&mut self.bar
|
|
|
|
|
}
|
|
|
|
|
fn into_bar(self) -> T { // Εδώ το self καταναλώνεται
|
|
|
|
|
self.bar
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let a_foo = Foo { bar: 1 };
|
|
|
|
|
println!("{}", a_foo.bar()); // 1
|
|
|
|
|
|
|
|
|
|
// Χαρακτηρηστικά (traits) (γνωστά ως interfaces ή typeclasses σε άλλες γλώσσες) //
|
|
|
|
|
|
|
|
|
|
trait Frobnicate<T> {
|
|
|
|
|
fn frobnicate(self) -> Option<T>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> Frobnicate<T> for Foo<T> {
|
|
|
|
|
fn frobnicate(self) -> Option<T> {
|
|
|
|
|
Some(self.bar)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let another_foo = Foo { bar: 1 };
|
|
|
|
|
println!("{:?}", another_foo.frobnicate()); // Some(1)
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
// 3. Αντιστοιχίσεις Μοτίβων (Pattern Matching) //
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
let foo = OptionalI32::AnI32(1);
|
|
|
|
|
match foo {
|
|
|
|
|
OptionalI32::AnI32(n) => println!("Είναι ένα i32: {}", n),
|
|
|
|
|
OptionalI32::Nothing => println!("Δεν είναι τίποτα!"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Προχωρημένο pattern matching
|
|
|
|
|
struct FooBar { x: i32, y: OptionalI32 }
|
|
|
|
|
let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) };
|
|
|
|
|
|
|
|
|
|
match bar {
|
|
|
|
|
FooBar { x: 0, y: OptionalI32::AnI32(0) } =>
|
|
|
|
|
println!("Οι αριθμοί είναι μηδέν!"),
|
|
|
|
|
FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m =>
|
|
|
|
|
println!("Οι αριθμοί είναι οι ίδιοι"),
|
|
|
|
|
FooBar { x: n, y: OptionalI32::AnI32(m) } =>
|
|
|
|
|
println!("Διαφορετικοί αριθμοί: {} {}", n, m),
|
|
|
|
|
FooBar { x: _, y: OptionalI32::Nothing } =>
|
|
|
|
|
println!("Ο δεύτερος αριθμός δεν είναι τίποτα!"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////
|
|
|
|
|
// 4. Έλεγχος ροής //
|
|
|
|
|
/////////////////////
|
|
|
|
|
|
|
|
|
|
// Βρόγχοι `for`
|
|
|
|
|
let array = [1, 2, 3];
|
2021-11-02 00:27:42 +03:00
|
|
|
|
for i in array {
|
2020-10-14 11:29:08 +03:00
|
|
|
|
println!("{}", i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Διαστήματα
|
|
|
|
|
for i in 0u32..10 {
|
|
|
|
|
print!("{} ", i);
|
|
|
|
|
}
|
|
|
|
|
println!("");
|
|
|
|
|
// Τυπώνει `0 1 2 3 4 5 6 7 8 9 `
|
|
|
|
|
|
|
|
|
|
// Βρόγχοι `if`
|
|
|
|
|
if 1 == 1 {
|
|
|
|
|
println!("Τα μαθηματικά δουλεύουν!");
|
|
|
|
|
} else {
|
|
|
|
|
println!("Ωχ όχι...");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// `if` ως έκφραση
|
|
|
|
|
let value = if true {
|
|
|
|
|
"καλό"
|
|
|
|
|
} else {
|
|
|
|
|
"κακό"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Βρόγχοι `while`
|
|
|
|
|
while 1 == 1 {
|
|
|
|
|
println!("Το σύμπαν λειτουργεί κανονικά.");
|
|
|
|
|
// Μπορούμε να βγούμε από το βρόγχο με το `break`
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ατέρμονος βρόχγος
|
|
|
|
|
loop {
|
|
|
|
|
println!("Καλημέρα!");
|
|
|
|
|
// Μπορούμε να βγούμε από το βρόγχο με το `break`
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////
|
|
|
|
|
// 5. Ασφάλεια μνήμης & δείκτες //
|
|
|
|
|
//////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Δείκτης με ιδιοκτήτη – μόνο ένα αντικείμενο μπορεί να είναι ο "ιδιοκτήτης" αυτού του δείκτη ανά πάσα στιγμή
|
|
|
|
|
// Αυτό σημαίνει ότι μόλις το `Box` βγει εκτός πλαισίου (out of scope), ο δείκτης μπορεί να ελευθερωθεί με ασφάλεια
|
|
|
|
|
let mut mine: Box<i32> = Box::new(3);
|
|
|
|
|
*mine = 5; // Dereference του δείκτη
|
|
|
|
|
// Εδώ, το `now_its_mine` γίνεται ιδιοκτήτης του `mine`. Δηλαδή, το `mine` μετακινείται.
|
|
|
|
|
let mut now_its_mine = mine;
|
|
|
|
|
*now_its_mine += 2;
|
|
|
|
|
|
|
|
|
|
println!("{}", now_its_mine); // 7
|
|
|
|
|
// println!("{}", mine); // Αυτό παράγει λάθος κατά τη μεταγλώττιση διότι τώρα ο δείκτης ανοίκει στο `now_its_mine`
|
|
|
|
|
|
|
|
|
|
// Reference (αναφορά) – ένας αμετάβλητος δείκτης που αναφέρεται σε άλλα δεδομένα
|
|
|
|
|
// Όταν μια αναφορά δίνεται σε μια αξία, λέμε πως η αξία έχει "δανειστεί".
|
|
|
|
|
// Όταν μια αξία δανείζεται αμετάβλητα, δεν μπορεί να είναι mutated (να μεταβληθεί) ή να μετακινηθεί.
|
|
|
|
|
// Ένας "δανεισμός" παραμένει ενεργός μέχρι την τελευταία χρήση της μεταβλητής που δανείζεται.
|
|
|
|
|
let mut var = 4;
|
|
|
|
|
var = 3;
|
|
|
|
|
let ref_var: &i32 = &var;
|
|
|
|
|
|
|
|
|
|
println!("{}", var); // Αντίθετα με το `mine` προηγουμένως, η μεταβλητή `var` μπορεί ακόμα να χρησιμοποιηθεί
|
|
|
|
|
println!("{}", *ref_var);
|
|
|
|
|
// var = 5; // Αυτό παράγει λάθος κατά τη μεταγλώττιση γιατί η μεταβλητή `var` είναι δανεισμένη
|
|
|
|
|
// *ref_var = 6; // Το ίδιο εδώ, γιατί η `ref_var` αποτελεί αμετάβλητη αναφορά
|
|
|
|
|
ref_var; // Εντολή no-op (τίποτα δεν εκτελείται από τον επεξεργαστή), η οποία όμως μετράει ως χρήση και κρατά τον
|
|
|
|
|
// "δανεισμό" ενεργό
|
|
|
|
|
var = 2; // Η `ref_var` δεν χρησιμοποιείται από εδώ και στο εξής, άρα ο "δανεισμός" τελειώνει
|
|
|
|
|
|
|
|
|
|
// Μεταβλητή αναφορά
|
|
|
|
|
// Όσο μια αξία είναι μεταβλητά δανεισμένη, παραμένει τελείως απροσβάσιμη.
|
|
|
|
|
let mut var2 = 4;
|
|
|
|
|
let ref_var2: &mut i32 = &mut var2;
|
|
|
|
|
*ref_var2 += 2; // Ο αστερίσκος (*) χρησιμοποιείται ως δείκτης προς την μεταβλητά δανεισμένη `var2`
|
|
|
|
|
|
|
|
|
|
println!("{}", *ref_var2); // 6 , // Αν είχαμε `var2` εδώ θα προκαλούνταν λάθος μεταγλώττισης.
|
|
|
|
|
// O τύπος της `ref_var2` είναι &mut i32, άρα αποθηκεύει μια αναφορά προς μια αξία i32, όχι την αξία την ίδια.
|
|
|
|
|
// var2 = 2; // Λάθος μεταγλώττισης, γιατί η `var2` είναι δανεισμένη.
|
|
|
|
|
ref_var2; // Εντολή no-op (τίποτα δεν εκτελείται από τον επεξεργαστή), η οποία όμως μετράει ως χρήση και κρατά τον
|
|
|
|
|
// "δανεισμό" ενεργό
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Μάθετε περισσότερα
|
|
|
|
|
|
|
|
|
|
Υπάρχουν πολλά ακόμα πράγματα να μάθει κανείς· αυτά είναι μόνο τα βασικά της Rust, που επιτρέπουν να καταλάβουμε το
|
|
|
|
|
βασικό τρόπο λειτουργίας της. Για να μάθετε περισσότερα για τη Rust, διαβάστε το [The Rust Programming
|
|
|
|
|
Language](http://doc.rust-lang.org/book/index.html) και επισκεφθείτε το subreddit [/r/rust](http://reddit.com/r/rust).
|
|
|
|
|
Οι άνθρωποι πίσω από το κανάλι #rust στο irc.mozilla.org είναι επίσης πάντα πρόθυμοι να βοηθήσουν τους αρχάριους.
|
|
|
|
|
|
|
|
|
|
Μπορείτε επίσης να παίξετε με τη Rust χρησιμοποιώντας τους εξής online μεταγλωττιστές:
|
|
|
|
|
|
|
|
|
|
- [Rust playpen](http://play.rust-lang.org)
|
|
|
|
|
- [Rust website](http://rust-lang.org)
|