5 votes

En Rust, lors de la mise en boîte d'une valeur passée en tant qu'argument générique, pourquoi un lien de durée de vie `'static'' est-il nécessaire ?

J'essaie d'écrire une fonction constructrice qui prend en argument une valeur générique implémentant un certain trait, puis la met en boîte (le but est d'initialiser ensuite quelque chose avec ces boîtes, mais l'exemple suivant est simplifié) :

struct Struct {}

trait Trait {}

impl Trait for Struct {}

fn f(arg: impl Trait) -> Box<dyn Trait> {
    Box::new(arg)
}

fn main() {
    let x = Struct {};
    f(x);
}

Ici, le compilateur se plaint que arg pourrait ne pas vivre assez longtemps. Cela me semble parfaitement logique, car la seule exigence sur arg est impl Trait ce qui signifie qu'il peut s'agir en fait d'une référence qui implémente le trait, auquel cas il ne peut pas être encadré de manière sûre.

Ce qui m'embrouille, c'est la solution suivante, qui consiste à ajouter un 'static liés :

fn f(arg: impl Trait + 'static) -> Box<dyn Trait> {
    Box::new(arg)
}

Bien sûr, cela fonctionne, mais en principe, nous sommes maintenant contraints de transmettre des valeurs avec une balise 'static vie. Pourtant, le compilateur me laisse passer dans x sans problème.

Voici mes questions, plus précisément :

  1. Non. x ont une vie, résidant sur la pile ? Pourquoi est-il possible de le passer à f quand arg a un 'static la limite de durée de vie ? Ces limites ne concernent-elles que la durée de vie des références ?
  2. Cette solution est-elle valable en général, ou vais-je rencontrer des cas où le compilateur refusera mes arguments alloués par pile ?
  3. Y a-t-il une façon plus agréable de dire "tout type qui implose" ? Trait où le type n'est pas une référence ?

Notez que la réponse à la question 1) est principalement donnée par Pourquoi Rust exige-t-il une durée de vie ``statique`` pour cette variable ? mais je ne sais pas si c'est la façon idiomatique de présenter les arguments.


EDITAR:

Maintenant que je comprends mieux, je me demande quelle est la solution idiomatique pour corriger l'erreur de compilation dans le cas du remplissage d'une structure :

struct OtherStruct {
    x: Box<dyn Trait>,
}

impl OtherStruct {
    fn new(arg: impl Trait) -> Self { // Does not compile
        Self { x: Box::new(arg) }
    }
}

Les seules solutions que je vois jusqu'à présent sont 1) l'ajout d'un paramètre de durée de vie à l'adresse suivante OtherStruct (pas si bien), en ajoutant un 'static durée de vie liée à arg (Je ne suis pas sûr que ce soit correct ?)

4voto

Colonel Thirty Two Points 3617

Vous avez quelques idées fausses ici.

Est-ce que x n'a pas une durée de vie, résidant sur la pile ? Pourquoi est-il possible de le passer à f alors que arg a une "durée de vie statique" ? Ces limites ne concernent-elles que la durée de vie des références ?

Quand vous faites f(x) parce que vous ne prenez pas une référence à x vous êtes déménagement la valeur de x dans la fonction, ce qui décale sa durée de vie. Si vous essayez d'utiliser x à nouveau après avoir appelé f(x) Rust ne compilera pas votre code et vous le dira.

Quant à la + 'static lié... Box<dyn Trait> est un raccourci pour Box<dyn Trait + 'static> c'est pourquoi le compilateur vous a donné une erreur. Le système de types doit connaître la durée de vie de l'implémentation à l'intérieur de la boîte afin de pouvoir la vérifier. Vous pouvez donner à la boîte une durée de vie différente, si vous le souhaitez, de manière explicite :

fn f<'a>(arg: impl Trait + 'a) -> Box<dyn Trait + 'a> {
    Box::new(arg)
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X