rust — συγκεντρωτικός οδηγός — DedSec Project
rust — συγκεντρωτικός οδηγός Rust Συνήθης χρήση: Προγραμματισμός συστημάτων. Προτεινόμενη επέκταση αρχείου: .rs . Εκτέλεση / περιβάλλον: rustc main.rs && ./main. Αρχικό παράδειγμα Πώς…
Rust
Συνήθης χρήση: Προγραμματισμός συστημάτων.
Προτεινόμενη επέκταση αρχείου: .rs.
Εκτέλεση / περιβάλλον: rustc main.rs && ./main.
Αρχικό παράδειγμα
fn greet(name: &str) -> String { format!("Hello, {}!", name) }
fn main() { println!("{}", greet("Ada")); }
Πώς διαβάζεται
Η ιδιοκτησία και ο δανεισμός αποτρέπουν πολλά σφάλματα μνήμης.
Συνηθισμένο λάθος
Η ιδιοκτησία και ο δανεισμός αποτρέπουν πολλά σφάλματα μνήμης. Έλεγξε την έκδοση διερμηνευτή/μεταγλωττιστή και μην εκλαμβάνεις το δείγμα ως έτοιμη εφαρμογή παραγωγής.
Ownership και borrowing στη Rust
Η Rust εμποδίζει πολλά use-after-free στη μεταγλώττιση: μία τιμή έχει έναν owner, το &T είναι κοινός immutable δανεισμός και το &mut T αποκλειστικός mutable δανεισμός.
fn total(values: &[i32]) -> i32 {
values.iter().sum()
}
fn main() {
let values = vec![10, 20, 30];
assert_eq!(total(&values), 60);
println!("{}", values.len()); // το borrow δεν μεταφέρει ownership
}
Το Result<T,E> και ο τελεστής ? βοηθούν στον χειρισμό λαθών. Το Option<T> εκφράζει απουσία χωρίς null pointer. Απόφυγε unwrap() σε απρόβλεπτο input. Το Cargo παρέχει cargo check, cargo test, cargo clippy όπου έχουν εγκατασταθεί.
Άσκηση: υλοποίησε parse_positive(&str)->Result<u32,String>, έλεγξε 0, αρνητικά, άκυρο κείμενο και θετικά. Εξήγησε move String έναντι borrow &str. Πηγή: https://doc.rust-lang.org/book/.
Rust: ιδιοκτησία, Result και οριακά tests
Οι κανόνες ownership της Rust καθορίζουν ποιος τροποποιεί δεδομένα και πόσο ισχύουν οι αναφορές. Δοκίμασε:
fn nonempty_name(input: &str) -> Result<&str, &'static str> {
let name = input.trim();
if name.is_empty() { return Err("empty name"); }
Ok(name)
}
fn main() {
assert_eq!(nonempty_name(" Ada ").unwrap(), "Ada");
assert!(nonempty_name(" ").is_err());
}
Το αποτέλεσμα δανείζεται ένα slice από την είσοδο αντί να δημιουργεί String. Γιατί δεν μπορεί μια συνάρτηση να επιστρέψει ασφαλώς αναφορά σε προσωρινό String που δημιουργήθηκε μέσα της; Το αντικείμενο καταστρέφεται στο return. Δοκίμασε τέτοιο λανθασμένο παράδειγμα και ερμήνευσε το lifetime error αντί να το παρακάμψεις.
Φτιάξε δεύτερη υλοποίηση που επιστρέφει owned String ώστε ο caller να μην εξαρτάται από τη διάρκεια ζωής της εισόδου. Σύγκρινε API contract και ενδεχόμενη allocation. Διαχειρίσου Ok/Err με match χωρίς panic. Έλεγξε κενό, spaces, Unicode και συνηθισμένο όνομα.
Για compile error προσδιόρισε αν αφορά τύπους, move, borrow ή lifetime και μείωσε το δείγμα. Μη χρησιμοποιείς unsafe για να καλύψεις ασάφεια ownership.
Επαλήθευση: τα tests περνούν και εξηγείς γιατί το borrowed slice απαιτεί ζωντανή αρχική είσοδο. Πηγή: https://doc.rust-lang.org/stable/book/ch09-00-error-handling.
Rust — Αναλυτικός οδηγός εξάσκησης
Στόχος
Ένας parser θετικών u16 πρέπει να επιστρέφει Result αντί να τερματίζει με panic. Οι αναφορές δανείζονται δεδομένα και το String κατέχει τη μνήμη του. Το map_err δείχνει γιατί ο τελεστής ? απαιτεί συμβατό τύπο σφάλματος στην επιστροφή.
Εκτέλεση
Αποθήκευσε main.rs. Εκτέλεσε rustc --test main.rs -o tests && ./tests και έπειτα rustc main.rs -o app && ./app. Περιμένεις επιτυχείς δοκιμές και Ok(42).
fn parse_limit(text: &str) -> Result<u16, String> {
let number: u16 = text.trim().parse()
.map_err(|_| "not a u16".to_string())?;
if number == 0 { return Err("must be positive".to_string()); }
Ok(number)
}
fn main() { println!("{:?}", parse_limit(" 42 ")); }
#[cfg(test)]
mod tests {
use super::parse_limit;
#[test]
fn boundaries() {
assert_eq!(parse_limit("42").unwrap(), 42);
for bad in ["0", "-1", "65536", "word"] {
assert!(parse_limit(bad).is_err());
}
}
}
Κατανόηση
Το trim δημιουργεί &str slice από την αρχική είσοδο. Η parse απορρίπτει αρνητικούς και υπερχείλιση u16. Η απόρριψη μηδενός είναι κανόνας της εφαρμογής, όχι του τύπου. Δοκίμασε να επιστρέψεις αναφορά σε String που δημιουργείται τοπικά: ο compiler σωστά την απορρίπτει επειδή καταστρέφεται ο ιδιοκτήτης.
Επέκταση
Πέρασε &input από δικό σου String και χρησιμοποίησε ξανά το input, αποδεικνύοντας ότι ο δανεισμός δεν το μετέφερε. Αντικατάστησε το String error με enum και χειρίσου το μέσω match αντί unwrap σε μη έμπιστη είσοδο. Έλεγξε κενά, 65535, 65536 και άδειο κείμενο.
Διάγνωση
E0382: συχνά χρήση τιμής μετά από move. E0502: αντικρουόμενοι δανεισμοί. Το rustc --version δείχνει toolchain, ενώ cargo test αφορά Cargo project. Μην κρύβεις σφάλματα ownership με unsafe. Επιτυχία: tests χωρίς panic και κατανόηση του slice. https://doc.rust-lang.org/book/
Rust — Παραδείγματα πραγματικού κώδικα
Εκτέλεση των παραδειγμάτων
Τα παραδείγματα είναι μικρά και αυτοτελή. Χρησιμοποίησε τη σχετική εγκατεστημένη γλώσσα. Ενδεικτικά: rustc {file} -o demo && ./demo. Μη συγχέεις τα ονόματα αρχείων με αυτόματη εγκατάσταση. Δούλεψε σε δοκιμαστικό φάκελο.
Rust — Διαδρομή ουσιαστικής εξάσκησης
Μικρό εργαστήριο με Option
Η μέθοδος get σε slice επιστρέφει Option και επιτρέπει διαχείριση απουσίας στοιχείου χωρίς panic. Το ? σε συνάρτηση που επιστρέφει Option προκαλεί πρόωρη επιστροφή None όταν λείπει τιμή. Το checked_add επιστρέφει None αντί να κάνει σιωπηρή αριθμητική υπερχείλιση.
fn first_two(values: &[i32]) -> Option<i32> {
let first = *values.get(0)?;
let second = *values.get(1)?;
first.checked_add(second)
}
fn main() {
assert_eq!(first_two(&[3, 5]), Some(8));
assert_eq!(first_two(&[]), None);
assert_eq!(first_two(&[i32::MAX, 1]), None);
}
Τα τρία assertions πρέπει να περάσουν στο κατάλληλο Rust compiler. Δεν χρειάζεται unsafe, ούτε ανεξέλεγκτη προσπέλαση με indexing. Δοκίμασε και το [9] ώστε να παρατηρήσεις ξεχωριστά το όριο μήκους.
Ο borrowing κανόνας που εμποδίζει dangling pointer
Φτιάξε προσωρινή συνάρτηση που προσπαθεί να επιστρέψει &i32 προς μεταβλητή που ζει μόνο μέσα στο body της. Ο compiler πρέπει να απορρίψει την αναφορά, επειδή ο δανειζόμενος θα έμενε χωρίς ενεργό owner. Η διόρθωση είναι να επιστρέψεις owned value ή να δανειστείς δεδομένα που ο caller έχει και διατηρεί.
Διαχωρισμός ownership και runtime logic
Η ύπαρξη ελέγχου δανεισμού δεν αποδεικνύει ότι το επιχειρησιακό αποτέλεσμα είναι σωστό. Ακόμη και code με μηδενικά unsafe blocks μπορεί να έχει λάθος μονάδες, μη έγκυρη λογική πολιτικής ή ανεπαρκή έλεγχο JSON. Γράψε unit test που αποτυγχάνει για μία λανθασμένη επιχειρησιακή υπόθεση χωρίς καμία παραβίαση μνήμης.
Παραδοτέο
Τρέξε cargo test με τρεις οριακές περιπτώσεις: κενή λίστα, overflow και κανονικό αποτέλεσμα. Κατάγραψε rustc και cargo versions, τη διάγνωση για το εσκεμμένο dangling reference και τη διαφορά του checked_add από μια απλή πρόσθεση σε debug/release build. Μην ισχυριστείς ότι το παράδειγμα εκτελέστηκε μέσα στο αρχείο γνώσης: τα αποτελέσματα που περιγράφονται είναι προβλέψεις προς επαλήθευση.
Rust — Τεχνικά σημεία και συχνές παγίδες
Τεχνική γνώση
- Η ιδιοκτησία και ο δανεισμός περιορίζουν αναφορές και χρόνο ζωής για ασφάλεια μνήμης.
- Το Result δηλώνει αποτυχία, το Option απουσία τιμής.
- Τα unsafe blocks απαιτούν ειδική τεκμηρίωση και δεν καταργούν όλους τους κανόνες ορθότητας.