τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
γεια σε όλους
Σήμερα ολοκλήρωσα το 2024 Autonomous Driving OS Development Training Camp - The Fourth Phase of the Elementary Camp - Tutorial
Ημέρα 2 Εξασκηθείτε στη γλώσσα Rust με θρόισμα-Σημασιολογία Μετακίνησης
https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html
Όταν υποβάλλω τον κωδικό, λαμβάνω ένα μήνυμα ότι δεν έχω άδεια Πώς μπορώ να βγω;
aciton
Διαμόρφωση περιβάλλοντος ανάπτυξης αναφοράς
https://rcore-os.cn/arceos-tutorial-book/ch01-02.html
το θέμα μου
https://github.com/cicvedu/rustlings-semester-4-watchpoints
Δημιουργήστε ένα κλειδί ssh για να κλωνοποιήσετε τον κώδικα github μέσω ssh. Στο περιβάλλον Linux, χρησιμοποιήστε την εντολή ssh-keygen -t rsa -b 4096 -C για να δημιουργήσετε ένα κλειδί ssh. Στη συνέχεια, χρησιμοποιήστε το cat ~/.ssh/id_rsa.pub
Το Rust έχει μερικούς βασικούς τύπους που εφαρμόζονται απευθείας στον μεταγλωττιστή. Σε αυτήν την ενότητα, θα περάσουμε από τα πιο σημαντικά.
Τα Slice Type Slices σάς επιτρέπουν να αναφέρετε μια συνεχόμενη ακολουθία στοιχείων σε μια συλλογή αντί για ολόκληρη τη συλλογή.
Ένα slice είναι ένα είδος αναφοράς, επομένως δεν έχει ιδιοκτησία.
Στο Rust, ένα slice είναι μια προβολή που αναφέρεται σε μια ακολουθία συνεχόμενων στοιχείων από έναν πίνακα ή μια άλλη φέτα. Για να δημιουργήσετε μια φέτα, πρέπει να καθορίσετε τις θέσεις έναρξης και τέλους της φέτας (χωρίς να περιλαμβάνεται ο δείκτης της θέσης λήξης).σε συστοιχίαa
αν θέλετε να πάρετε[2, 3, 4]
Για αυτό το κομμάτι, πρέπει να ξεκινήσετε από τον δείκτη 1 και να τελειώσετε στον δείκτη 4 (χωρίς να συμπεριλαμβάνεται ο δείκτης 4).
Δείτε πώς μπορείτε να διορθώσετε τον κωδικό δοκιμής σας:
#[test]
fn slice_out_of_array() {
let a = [1, 2, 3, 4, 5];
// 从索引 1 开始,到索引 4 结束的切片
let nice_slice = &a[1..4];
assert_eq!([2, 3, 4], nice_slice);
}
Σε αυτό το παράδειγμα,&a[1..4]
Δημιούργησε έναν πίνακα απόa
Το slice ξεκινά από το ευρετήριο 1 και τελειώνει στο ευρετήριο 3, επειδή η σύνταξη τεμαχισμού του Rust είναι ένα αριστερό-κλειστό και δεξιά-ανοιχτό διάστημα (συμπεριλαμβανομένης της αρχής, αλλά όχι του τέλους).Έτσιnice_slice
Περιέχει τον πίνακαa
Μέσης[2, 3, 4]
。
Εισαγάγετε το rustlings watch στη γραμμή εντολών για να ξεκινήσει το πείραμα βρόχου για την επεξεργασία του κώδικα
Κατανόηση της ιδιοκτησίας
Η ιδιοκτησία είναι το πιο μοναδικό χαρακτηριστικό του Rust και έχει βαθιές επιπτώσεις για την υπόλοιπη γλώσσα.
Επιτρέπει στο Rust να παρέχει εγγυήσεις για την ασφάλεια της μνήμης χωρίς να χρειάζεται συλλέκτης απορριμμάτων
Τι είναι η ιδιοκτησία;
Κανόνες ιδιοκτησίας Αρχικά, ας ρίξουμε μια ματιά στους κανόνες ιδιοκτησίας. Λάβετε υπόψη αυτούς τους κανόνες καθώς επεξεργαζόμαστε τα παραδείγματα που τους επεξηγούν:
Το ίδιο το δείγμα κώδικα είναι σωστό και δείχνει τις έννοιες της ιδιοκτησίας και της αντιγραφής στο Rust. Ωστόσο, εάν θέλετε να βεβαιωθείτε ότι ο κώδικάς σας μεταγλωττίζεται και εκτελείται και θέλετε να αντιμετωπίσετε ορισμένες πιθανές βελτιώσεις ή διορθώσεις, ακολουθούν ορισμένες προτάσεις:
συγουρεύομαι takes_ownership
καιmakes_copy
λειτουργία σεmain
λειτουργία που ορίστηκε προηγουμένως, επειδή οι συναρτήσεις στο Rust πρέπει πρώτα να δηλωθούν και μετά να χρησιμοποιηθούν.
προσθέστε σημειώσεις, εξήγησε γιατί s
υπάρχειtakes_ownership
δεν μπορεί να χρησιμοποιηθεί μετά την κλήση καιx
υπάρχειmakes_copy
Μπορεί ακόμα να χρησιμοποιηθεί μετά την κλήση.
Προσθήκη σε main
τύπος επιστροφής συνάρτησης, αν και αυτό δεν είναι απαραίτητο σε απλά προγράμματα, είναι μια καλή προγραμματιστική πρακτική.
Χρησιμοποιώντας τα εργαλεία μορφοποίησης του Rust,για παράδειγμα rustfmt
, για να διατηρήσετε τον κώδικα καθαρό.
Ακολουθεί ο τροποποιημένος κώδικας με βάση τις παραπάνω προτάσεις:
fn takes_ownership(some_string: String) { // 函数定义在 main 之前
println!("{}", some_string);
} // some_string 的作用域结束,调用 Drop
fn makes_copy(some_integer: i32) { // 函数定义在 main 之前
println!("{}", some_integer);
} // some_integer 的作用域结束,没有调用 Drop,因为 i32 是 Copy 类型
fn main() -> () { // 明确 main 函数的返回类型为 ()
let s = String::from("hello"); // s 拥有 "hello" 的所有权
takes_ownership(s); // s 的值移动到 takes_ownership 函数
// 下面的代码尝试使用 s 将会导致编译错误,因为 s 的值已经移动
// let len = s.len(); // 错误:s 已移动
let x = 5; // x 包含值 5
makes_copy(x); // x 的值被复制到 makes_copy 函数
// x 仍然有效,因为 i32 是 Copy 类型
// x 仍然可以使用
println!("x is {}", x);
}
Σε αυτήν την αναθεωρημένη έκδοση έχουμε προσθέσει main
τύπος επιστροφής συνάρτησης()
,αυτό σημαίνει main
Η συνάρτηση δεν επιστρέφει τιμή.Επίσης, προστίθενται σχόλια για να εξηγηθεί γιατίs
υπάρχειtakes_ownership
δεν μπορεί να χρησιμοποιηθεί μετά την κλήση καιx
υπάρχειmakes_copy
Εξακολουθεί να ισχύει μετά την κλήση.Επιπλέον, δείχνουμε προσπάθειες σεtakes_ownership
Χρήση μετά την κλήσηs
Παραδείγματα που θα προκαλούσαν σφάλματα μεταγλώττισης καιx
υπάρχειmakes_copy
Παραδείγματα που μπορούν ακόμα να χρησιμοποιηθούν μετά την κλήση.
Τα Vectors είναι μια από τις πιο χρησιμοποιούμενες δομές δεδομένων Rust.
Σε άλλες γλώσσες προγραμματισμού, θα ονομάζονταν απλά Arrays, αλλά επειδή το Rust λειτουργεί σε λίγο χαμηλότερο επίπεδο, ένας πίνακας στο Rust αποθηκεύεται στη στοίβα (που σημαίνει ότι δεν μπορεί να αναπτυχθεί ή να συρρικνωθεί και το μέγεθος πρέπει να είναι γνωστό κατά το χρόνο μεταγλώττισης) και ένα Vector αποθηκεύεται στο σωρό (όπου δεν ισχύουν αυτοί οι περιορισμοί).
Τα διανύσματα είναι λίγο μεταγενέστερο κεφάλαιο του βιβλίου, αλλά πιστεύουμε ότι είναι αρκετά χρήσιμα για να μιλήσουμε για αυτά λίγο νωρίτερα. Θα μιλήσουμε για την άλλη χρήσιμη δομή δεδομένων, τους χάρτες κατακερματισμού, αργότερα.
vec_map
Η λειτουργία είναι η αποδοχή αVec<i32>
τύπου (δηλαδή ένα διάνυσμα που περιέχει έναν ακέραιο αριθμό 32 bit), στη συνέχεια επιστρέφει ένα νέοVec<i32>
, κάθε στοιχείο σε αυτό το νέο διάνυσμα είναι διπλάσιο από το μέγεθος του αντίστοιχου στοιχείου στο αρχικό διάνυσμα.
ΕΙΔΙΚΑ,vec_map
σε λειτουργίαmap
καιcollect
Η μέθοδος λειτουργεί ως εξής:
**v.iter()
**: Αυτή η μέθοδος δημιουργεί έναν επαναλήπτη που διασχίζει v
κάθε στοιχείο του διανύσματος.iter
Ο επαναλήπτης που επιστρέφεται από τη μέθοδο παρέχει μια αμετάβλητη αναφορά στα στοιχεία του διανύσματος.
**.map(|element| { element * 2 })
**:map
Η μέθοδος δέχεται ένα κλείσιμο (ανώνυμη συνάρτηση), σε αυτήν την περίπτωση το κλείσιμο δέχεται μία παράμετροelement
(μια αμετάβλητη αναφορά σε ένα στοιχείο στο διάνυσμα), στη συνέχεια επιστρέφει την τιμή αυτού του στοιχείου πολλαπλασιαζόμενη επί 2.Λειτουργίες εντός κλεισίματοςelement * 2
Στην πραγματικότητα, αποαναφέρετε τα δεδομένα στα οποία επισημαίνεται η αναφορά (μέσω*
τελεστής) και να εκτελέσετε λειτουργίες πολλαπλασιασμού.
**.collect()
**:map
Η μέθοδος επιστρέφει έναν lazy iterator που εφαρμόζει τις λειτουργίες στο κλείσιμο μία προς μία, αλλά δεν συλλέγει τα αποτελέσματα αμέσως.collect
μέθοδος καλείται να περάσει αυτάmap
Τα επεξεργασμένα στοιχεία συλλέγονται σε ένα νέοVec<i32>
σε διάνυσμα.
χρήση map
καιcollect
Το πλεονέκτημα είναι ότι σας επιτρέπουν να εκτελείτε λειτουργίες σε κάθε στοιχείο της συλλογής με δηλωτικό τρόπο και να συλλέγετε τα αποτελέσματα σε μια νέα συλλογή χωρίς να χρειάζεται να γράψετε έναν ρητό βρόχο. Με αυτόν τον τρόπο ο κώδικας είναι πιο συνοπτικός και πιο συνεπής με το στυλ Rust.
Εδώ είναι ένας τρόπος χρήσης vec_map
Παράδειγμα συνάρτησης:
fn main() {
let original_vec = vec![1, 2, 3, 4];
let doubled_vec = vec_map(&original_vec);
println!("{:?}", doubled_vec); // 这将打印:[2, 4, 6, 8]
}
Σε αυτό το παράδειγμα,vec_map
αναλαμβάνωoriginal_vec
αναφοράς, δημιουργώντας ένα νέο διάνυσμαdoubled_vec
, το οποίο περιέχει τη διπλάσια τιμή κάθε στοιχείου του αρχικού διανύσματος και το εκτυπώνει.
Αυτές οι ασκήσεις είναι προσαρμοσμένες από pnkfelix'μικρό Οδηγός σκουριάς -- Σας ευχαριστώ Felix!!!
Για αυτήν την ενότητα, οι σύνδεσμοι των βιβλίων είναι ιδιαίτερα σημαντικοί.
Υπάρχει ένας κανόνας για τις μεταβλητές αναφορές στο Rust: ανά πάσα στιγμή, μπορείτε να έχετε οποιονδήποτε αριθμό αμετάβλητων αναφορών ή το πολύ μία μεταβλητή αναφορά. Αυτός ο κανόνας διασφαλίζει την ασφάλεια της μνήμης και αποτρέπει τους αγώνες δεδομένων.
Στον παρεχόμενο κωδικό, υπάρχει ένα πρόβλημα:main
Η συνάρτηση προσπάθησε να δημιουργήσει δύο μεταβλητές αναφορέςy
καιz
, και οι δύο δείχνουν στην ίδια μεταβλητή x
. Αυτό δεν επιτρέπεται επειδή οι κανόνες δανεισμού του Rust δεν επιτρέπουν πολλαπλές μεταβλητές αναφορές στην ίδια μεταβλητή στο ίδιο εύρος. Γι' αυτό ο κώδικας δεν μεταγλωττίζεται.
Για να επιλύσετε αυτό το πρόβλημα, πρέπει να βεβαιωθείτε ότι υπάρχει μόνο μία μεταβλητή αναφορά ανά πάσα στιγμή. Εδώ είναι ο σταθερός κωδικός:
fn main() {
let mut x = 100;
{
let y = &mut x;
*y += 100; // 此时 x 的值变为 200
} // 'y' 的作用域结束,可变引用被销毁
{
let z = &mut x; // 可以创建新的可变引用,因为 'y' 已经不存在了
*z += 1000; // 此时 x 的值变为 1200
} // 'z' 的作用域结束,可变引用被销毁
assert_eq!(x, 1200); // 断言 x 的值是 1200,这是正确的
}
Σε αυτήν τη σταθερή έκδοση, διασφαλίζουμε ότι υπάρχει μόνο μία μεταβλητή αναφορά ανά πάσα στιγμή, δημιουργώντας ένα εσωτερικό πεδίο εφαρμογής.Πρώτα δημιουργήσαμεy
εύρος, εκτελούνται λειτουργίες σε αυτό και, στη συνέχεια, αυτό το πεδίο εφαρμογής τελειώνει,y
Δεν είναι πλέον έγκυρο.Μετά από αυτό, δημιουργήσαμεz
εύρος, πάλι γιαx
Εκτελέστε λειτουργίες. Αυτό ακολουθεί τους κανόνες δανεισμού του Rust, έτσι ώστε ο κώδικας να μεταγλωττίζεται και να εκτελείται όπως αναμένεται.
Αυτό το μήνυμα σφάλματος μεταγλώττισης υποδεικνύει ένα ζήτημα κύκλου ζωής στον κώδικα Rust.Το ΠΡΟΒΛΗΜΑ ΕΙΝΑΙstring_uppercase
Κατά την υλοποίηση της συνάρτησης, επιχειρεί να εκχωρήσει μια προσωρινή τιμή σε μια αναφορά, η οποία δεν επιτρέπεται.
Εδώ είναι η γραμμή κώδικα που πάει στραβά:
data = &data.to_uppercase();
Σε αυτή τη γραμμή κώδικα,data.to_uppercase()
Δημιουργήθηκε αString
Ένα νέο παράδειγμα τουdata
δανεισμένος.Ωστόσο, δοκιμάστε να αντιστοιχίσετε μια αναφορά σε αυτήν την προσωρινή τιμήdata
είναι παράνομη γιατί η προσωρινή αξία καταστρέφεται αμέσως στο τέλος της δήλωσης καιdata
Απαιτεί μεγαλύτερη διάρκεια ζωής από τις προσωρινές τιμές.
Για να διορθώσουμε αυτό το πρόβλημα πρέπει να τροποποιήσουμε string_uppercase
Μια συνάρτηση που δέχεται μια μεταβλητή αναφορά και καλείται απευθείας στα δεδομένα που υποδεικνύει η αναφοράmake_uppercase()
μέθοδο αντί να προσπαθήσετε να εκχωρήσετε εκ νέου. Εδώ είναι ο σταθερός κωδικός:
fn string_uppercase(data: &mut String) {
data.make_uppercase(); // 直接在 data 上调用 make_uppercase 方法
println!("{}", data);
}
Σε αυτήν τη σταθερή έκδοση έχουμε αφαιρέσει mut data: &String
Μέσηςmut
,επειδή data
Ήδη μια μεταβλητή αναφορά.Μετά εμείς κατευθείανdata
καλώmake_uppercase()
, επομένως δεν θα υπάρχει πρόβλημα με τις προσωρινές τιμές.make_uppercase()
Η μέθοδος θα τροποποιηθείdata
σημεία αναφοράς σεString
παράδειγμα χωρίς να δημιουργήσετε ένα νέοString
。
επίσης,main
Η κλήση εντός της συνάρτησης πρέπει επίσης να ενημερωθεί ανάλογα για να περάσει μια μεταβλητή αναφορά:
fn main() {
let mut data = "Rust is great!".to_string();
string_uppercase(&mut data); // 传递一个可变引用
println!("{}", data); // 打印修改后的字符串
}
Τώρα,string_uppercase
η λειτουργία δέχεταιdata
μια μεταβλητή αναφορά, τροποποιήστε την απευθείας καιmain
σε λειτουργίαdata
είναι μεταβλητό και μπορεί να είναιstring_uppercase
τροποποιήθηκε. Με αυτόν τον τρόπο ο κώδικας μεταγλωττίζεται και λειτουργεί όπως αναμένεται.
/**
【昵称】小王同学
【坐标】山东
【自我介绍】
1. 高级后端工程师,擅长c++并发编程。
2. 专注分布式存储,分布式数据库。
3. 时间的践行者,立志成为一名讲师。
【我的成绩】
1. 为了走出农村,2次高考
一次考研失败,
遇挫之后不知道干什么,开启被动之旅。
2. 为了找到合适工作,
深入研究c++书籍和leetcode 200题目
3. 为了提高项目能力,参与开源项目建设。
4. 为了把简单事情说清楚/要干啥
按照《只管去做》,《福格行为模型>>方法。
纸上得来终觉浅,绝知此事要躬行
做一个践行者。
【我能提供】
1. 后端程序员的简历优化+就业辅导+职业规划
2. 全栈工程师(c++,rust,go,python )项目开发
3. 一年践行12本书践行记录。
【希望一起解决什么,开启破圈之旅】
1. 交接更多朋友,抱团取暖。
寻找意义本身就更加有意义。
2. 无法做整个系统,聚焦一个模块
道可道也,非恒道也
名可名也,非恒名也。
无名 万物之始也
有名 万物之母也
别想太多,只管去做,躬身入局
链接我: # + v(github):watchpoints
#众号:后端开发成长指南
**/
Αυτό το άρθρο είναι γραμμένο από mdniceΕκδόσεις πολλαπλών πλατφορμών