1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
---
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];
for i in array {
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)
|