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 :
- Non.
x
ont une vie, résidant sur la pile ? Pourquoi est-il possible de le passer àf
quandarg
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 ? - 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 ?
- 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 ?)