Partage de technologie

Jour 2 Pratiquez le langage Rust avec les bruissements-Move Semantics

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Bonjour à tous

Aujourd'hui, j'ai terminé le camp d'entraînement de développement du système d'exploitation de conduite autonome 2024 - La quatrième phase du camp élémentaire - Tutoriel

Jour 2 Pratiquez le langage Rust avec les bruissements-Move Semantics

autre
autre
autre

https://doc.rust-lang.org/stable/book/ch04-00-comprendre-la-propriete.html

Lorsque je soumets le code, je reçois un message indiquant que je n’ai pas l’autorisation. Comment puis-je sortir ?

autre
autre

action

autre

Configuration de l'environnement de développement de référence

https://rcore-os.cn/arceos-tutorial-book/ch01-02.html

mon sujet

https://github.com/cicvedu/rustlings-semestre-4-points-de-regard

Créez une clé ssh pour cloner le code github via ssh. Dans l'environnement Linux, utilisez la commande ssh-keygen -t rsa -b 4096 -C "votre boîte aux lettres" pour créer une clé ssh. Appuyez simplement sur Entrée pour toutes les options suivantes. Ensuite, utilisez cat ~/.ssh/id_rsa.pub

Types primitifs

Rust possède quelques types de base qui sont directement implémentés dans le compilateur. Dans cette section, nous allons passer en revue les plus importants.

Informations complémentaires

autre

Le type de tranche Les tranches vous permettent de référencer une séquence contiguë d'éléments dans une collection plutôt que la collection entière.

Une tranche est une sorte de référence, elle n'a donc pas de propriété.

autre
autre

Dans Rust, une tranche est une vue qui fait référence à une séquence d'éléments contigus provenant d'un tableau ou d'une autre tranche. Pour créer une tranche, vous devez spécifier les positions de début et de fin de la tranche (sans compter l'index de la position de fin).dans un tableaua inscrivez-vous si vous voulez obtenir[2, 3, 4] Pour cette tranche, vous devez commencer à l'index 1 et terminer à l'index 4 (sans compter l'index 4).

Voici comment corriger votre code de test :

#[test]
fn slice_out_of_array() {
    let a = [12345];

    // 从索引 1 开始,到索引 4 结束的切片
    let nice_slice = &a[1..4];

    assert_eq!([234], nice_slice);
}
  • 1

Dans cet exemple,&a[1..4] Créé un tableau à partir dea La tranche commence à l'index 1 et se termine à l'index 3, car la syntaxe de découpage de Rust est un intervalle fermé à gauche et ouvert à droite (incluant le début, mais pas la fin).doncnice_slice Il contient le tableaua milieu[2, 3, 4]

Entrez rustlings watch sur la ligne de commande pour démarrer l'expérience en boucle d'édition du code

autre

Comprendre la propriété

La propriété est la fonctionnalité la plus unique de Rust et a de profondes implications pour le reste du langage.

Il permet à Rust de garantir la sécurité de la mémoire sans avoir besoin d'un ramasse-miettes.

Qu'est-ce que la propriété ?

autre

Règles de propriété Commençons par examiner les règles de propriété. Gardez ces règles à l'esprit lorsque nous étudions les exemples qui les illustrent :

  • Chaque valeur dans Rust a un propriétaire.
  • Il ne peut y avoir qu'un seul propriétaire à la fois.
  • Lorsque le propriétaire sort du champ d'application, la valeur sera supprimée

autre
autre

L'exemple de code lui-même est correct et démontre les concepts de propriété et de copie dans Rust. Cependant, si vous souhaitez vous assurer que votre code est compilé et exécuté et que vous souhaitez apporter certaines améliorations ou corrections possibles, voici quelques suggestions :

  1. s'assurer takes_ownership etmakes_copy fonctionner dansmain fonction définie avant, car les fonctions dans Rust doivent d'abord être déclarées puis utilisées.

  2. ajouter des notes, expliquer pourquoi s existertakes_ownership ne peut pas être utilisé après avoir été appelé, etx existermakes_copy Il peut toujours être utilisé après avoir été appelé.

  3. Ajouter à main type de retour de fonction, bien que cela ne soit pas nécessaire dans les programmes simples, c'est une bonne pratique de programmation.

  4. Utiliser les outils de formatage de Rust,Par exemple rustfmt, pour garder le code propre.

Voici le code modifié basé sur les suggestions ci-dessus :

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);
}
  • 1

Dans cette version révisée, nous avons ajouté main type de retour de fonction(),cela signifie main La fonction ne renvoie aucune valeur.De plus, des commentaires sont ajoutés pour expliquer pourquois existertakes_ownership ne peut pas être utilisé après avoir été appelé, etx existermakes_copy Toujours valable après appel.De plus, nous montrons des tentatives pourtakes_ownership Utiliser après avoir appelés Exemples qui provoqueraient des erreurs de compilation, etx existermakes_copy Exemples qui peuvent encore être utilisés après appel.

Vecteurs

Les vecteurs sont l’une des structures de données Rust les plus utilisées.

Dans d'autres langages de programmation, ils seraient simplement appelés tableaux, mais comme Rust fonctionne à un niveau un peu inférieur, un tableau dans Rust est stocké sur la pile (ce qui signifie qu'il ne peut pas grandir ou diminuer, et la taille doit être connue au moment de la compilation), et un vecteur est stocké dans le tas (où ces restrictions ne s'appliquent pas).

Les vecteurs sont traités plus tard dans le livre, mais nous pensons qu'ils sont suffisamment utiles pour en parler un peu plus tôt. Nous parlerons de l'autre structure de données utile, les tables de hachage, plus tard.

Informations complémentaires

autre vec_map La fonction est d'accepter unVec<i32> type (c'est-à-dire un vecteur contenant un entier de 32 bits), puis renvoie un nouveauVec<i32>, chaque élément de ce nouveau vecteur est deux fois plus grand que l'élément correspondant dans le vecteur d'origine.

Spécifiquement,vec_map en fonctionmap etcollect La méthode fonctionne comme ceci :

  1. **v.iter()** : Cette méthode crée un itérateur qui parcourt v chaque élément du vecteur.iter L'itérateur renvoyé par la méthode fournit une référence immuable aux éléments du vecteur.

  2. **.map(|element| { element * 2 })**:map La méthode accepte une fermeture (fonction anonyme), dans ce cas la fermeture accepte un paramètreelement (une référence immuable à un élément du vecteur), renvoie ensuite la valeur de cet élément multipliée par 2.Opérations à l’intérieur des fermetureselement * 2 En fait, vous déréférencez les données pointées par la référence (via* opérateur) et effectuer des opérations de multiplication.

  3. **.collect()**:map La méthode renvoie un itérateur paresseux qui applique les opérations de fermeture une par une, mais ne collecte pas les résultats immédiatement.collect la méthode est appelée pour transmettre cesmap Les éléments traités sont collectés dans un nouveauVec<i32> en vecteur.

utiliser map etcollect L'avantage est qu'ils vous permettent d'effectuer des opérations sur chaque élément de la collection de manière déclarative et de collecter les résultats dans une nouvelle collection sans avoir besoin d'écrire des boucles explicites. De cette façon, le code est plus concis et plus cohérent avec le style Rust.

Voici comment utiliser vec_map Exemple de fonction :

fn main() {
    let original_vec = vec![1234];
    let doubled_vec = vec_map(&original_vec);
    println!("{:?}", doubled_vec); // 这将打印:[2, 4, 6, 8]
}
  • 1

Dans cet exemple,vec_map reprendreoriginal_vec référence, création d'un nouveau vecteurdoubled_vec, qui contient deux fois la valeur de chaque élément du vecteur d'origine et l'imprime.

Sémantique du déplacement

Ces exercices sont adaptés de pnkfélix's Tutoriel sur Rust -- Merci Félix !!!

Informations complémentaires

Pour cette section, les liens vers les livres sont particulièrement importants.

move_semantics1.rs

autre

move_semantics2.rs

autre
autre

// move_semantics5.rs

autre

Il existe une règle pour les références mutables dans Rust : à tout moment, vous pouvez avoir n'importe quel nombre de références immuables, ou au plus une référence mutable. Cette règle garantit la sécurité de la mémoire et empêche les courses de données.

Dans le code fourni, il y a un problème :main La fonction a tenté de créer deux références mutablesy etz, les deux pointent vers la même variable x . Ceci n'est pas autorisé car les règles d'emprunt de Rust n'autorisent pas plusieurs références mutables à la même variable dans la même portée. C'est pourquoi le code ne se compile pas.

Pour résoudre ce problème, vous devez vous assurer qu’une seule référence mutable existe à un moment donné. Voici le code fixe :

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,这是正确的
}
  • 1

Dans cette version corrigée, nous garantissons qu'une seule référence mutable existe à tout moment en créant une portée interne.Dans un premier temps, nous avons crééy portée, une opération est effectuée dessus, puis cette portée se termine,y N'est plus valide.Après cela, nous avons crééz portée, encore une fois pourx Effectuer des opérations. Cela suit les règles d'emprunt de Rust afin que le code soit compilé et exécuté comme prévu.

autre
autre
autre

Ce message d'erreur de compilation indique un problème de cycle de vie dans le code Rust.Le problème eststring_uppercase Lors de l'implémentation de la fonction, il tente d'attribuer une valeur temporaire à une référence, ce qui n'est pas autorisé.

Voici la ligne de code qui ne va pas :

data = &data.to_uppercase();
  • 1

Dans cette ligne de code,data.to_uppercase() A créé unString Un nouvel exemple dedata emprunté.Cependant, essayez d'attribuer une référence à cette valeur temporaire àdata est illégal car la valeur temporaire est détruite immédiatement à la fin de l'instruction, etdata Nécessite une durée de vie plus longue que les valeurs temporaires.

Pour résoudre ce problème, nous devons modifier string_uppercase Une fonction qui accepte une référence mutable et est appelée directement sur les données pointées par la référencemake_uppercase() méthode au lieu d’essayer de réaffecter. Voici le code fixe :

fn string_uppercase(data: &mut String) {
    data.make_uppercase(); // 直接在 data 上调用 make_uppercase 方法

    println!("{}", data);
}
  • 1

Dans cette version corrigée, nous avons supprimé mut data: &String milieumut,parce que data Déjà une référence mutable.Ensuite, nous directementdata demandermake_uppercase(), il n'y aura donc aucun problème avec les valeurs temporaires.make_uppercase() La méthode sera modifiéedata points de référence pourString instance sans en créer une nouvelleString

aussi,main L'appel au sein de la fonction doit également être mis à jour en conséquence pour transmettre une référence mutable :

fn main() {
    let mut data = "Rust is great!".to_string();

    string_uppercase(&mut data); // 传递一个可变引用
    println!("{}", data); // 打印修改后的字符串
}
  • 1

Maintenant,string_uppercase la fonction acceptedata une référence mutable, modifiez-la directement, etmain en fonctiondata est mutable et peut êtrestring_uppercase modifié. De cette façon, le code se compile et fonctionne comme prévu.

autre
autre
autre
/**
【昵称】小王同学
【坐标】山东
【自我介绍】
    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   
        #众号:后端开发成长指南
**/
  • 1

Cet article est écrit par mdnicePublication multiplateforme