Rust => OwnerShip

Le problème exposé dans ce sujet a été résolu.

Hello,

Slt !

J’ai du mal à comprendre l’ownership en Rust

Prantagoniste

En Rust, l’ownership est une règle implicite imposée par le compilateur. Elle vise à systématiquement vérifier qui dispose de quoi pour libérer correctement la mémoire lorsqu’on sort du scope de la ressource (j’y reviendrai rapidement). Ici, foo a l'ownership sur un objet Foo.

fn main() {
    let foo: Foo = Foo;
}

On comprend alors que foo est, en quelque sorte, le propriétaire de cette ressource et, lorsqu’elle sera traitée (de diverses manières), elle devra soit être transférée (changement de propriétaire) soit empruntée (accès à une référence en lecture/écriture, mais pas de transfert).

Je te laisse un exemple pour assimiler:

#[derive(Debug)]
struct Foo;

fn main() {
    let foo: Foo = Foo;

    // On emprunte l'objet `foo` en lecture seule.
    let bar: &Foo = &foo;

    super_foo_factory(foo);

    println!("{:?}", bar);
}

// Ici, la fonction prend un paramètre dont la ressource
// doit forcément être transférée.
fn super_foo_factory(f: Foo) -> Foo {
    /* ... On traite l'objet ... */
    f
}

Avec super_foo_factory, même principe. Les fonctions peuvent devenir, temporairement, propriétaires d’une ressource et ainsi protéger son utilisation ailleurs. A la fin de son exécution, f sera désalloué.

Seulement, là, il y a une erreur de compilation voulue. Le compilateur faisant la distinction entre un emprunt et un transfert, il ne laissera jamais passer ce que nous avons écrit. Une référence ne peut être la garante de la disponibilité de la ressource.

En espérant que ça puisse t’aider.

EDIT:

Scope et lifetime

Les notions de scope et de lifetime sont étroitement liées. A sa création, chaque ressource dispose d’un scope. Chaque scope dispose d’une durée de vie régissant la disponibilité d’une ressource.

Reprenons notre exemple de base.

struct Foo;

fn main() {
    let foo: Foo = Foo;
}

En analysant le code ci-dessus, un débutant ne remarquerait rien d’autre qu’une allocation d’un objet. En revanche, si on prête attention au code MIR, on peut en apprendre un peu plus concernant la gestion de la mémoire du compilateur.

fn main() -> (){
    let mut _0: ();                      // return place
    scope 1 {
        let _1: Foo;                     // "foo" in scope 1 at src/main.rs:4:9: 4:12
    }
    scope 2 {
    }

    bb0: {                              
        StorageLive(_1);                 // bb0[0]: scope 0 at src/main.rs:4:9: 4:12
        StorageDead(_1);                 // bb0[1]: scope 0 at src/main.rs:5:1: 5:2
        return;                          // bb0[2]: scope 0 at src/main.rs:5:2: 5:2
    }
}

A la ligne 3, notre identificateur foo a été renommé en _1. On constate également la création du scope 1, puis la destruction de la ressource à partir des lignes 10 et 11.

On peut également créer artificiellement des scopes pour des ressources dont la durée de vie ne doit pas excéder un court moment.

struct Foo;

fn main() {
    let mut foo;
    
    {
        foo = Foo;
        /* On effectue nos traitements... */
        let bar = Foo;
        /* On effectue nos traitements... */
    }
}

Code MIR:

fn main() -> (){
    let mut _0: ();                      // return place
    scope 1 {
        let mut _1: Foo;                 // "foo" in scope 1 at src/main.rs:4:9: 4:16
        scope 3 {
            let _2: Foo;                 // "bar" in scope 3 at src/main.rs:9:13: 9:16
        }
        scope 4 {
        }
    }
    scope 2 {
    }

    bb0: {                              
        StorageLive(_1);                 // bb0[0]: scope 0 at src/main.rs:4:9: 4:16
        StorageLive(_2);                 // bb0[1]: scope 1 at src/main.rs:9:13: 9:16
        StorageDead(_2);                 // bb0[2]: scope 1 at src/main.rs:11:5: 11:6
        StorageDead(_1);                 // bb0[3]: scope 0 at src/main.rs:18:1: 18:2
        return;                          // bb0[4]: scope 0 at src/main.rs:18:2: 18:2
    }
}
  • Ligne 3, on a notre scope "artificiel";
  • Ligne 5, on a le scope de bar.

Il suffit ensuite de simplement regarder, c’est explicite. :)

+1 -0

Sorry pour le double post, mais si tu as trouvé une solution, merci d’en publier la source ici (ou de surligner mon message si c’est ce qui t’a aidé). Les forums servent avant tout à aider les lecteurs à régler leurs soucis efficacement sans avoir à recommencer le travail de recherche.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte