Les références à des traits dans les structures
J'ai un trait Foo
pub trait Foo {
fn do_something(&self) -> f64;
}
et une structure qui de références que le trait
pub struct Bar {
foo: Foo,
}
En essayant de compiler je obtenir
error: reference to trait `Foo` where a type is expected; try `Box<Foo>` or `&Foo`
La modification de la structure de
struct Bar {
foo: &Foo,
}
Me dit error: missing lifetime specifier
De changer la définition
struct Bar {
foo: Box<Foo>,
}
Compile — yay!
Cependant, quand je veux une fonction pour retourner foo
sur bar
- quelque chose comme:
impl Bar {
fn get_foo(&self) -> Foo {
self.foo
}
}
Bien évidemment bar.foo
est un Box<Foo>
, donc évidemment je obtenir error: reference to trait `Foo` where a type is expected; try `Box<Foo>` or `&Foo`
La modification de la signature de
impl Bar {
fn get_foo(&self) -> Box<Foo> {
let this = *self;
this.foo
}
}
Mais maintenant je reçois error: cannot move out of dereference of `&`-pointer
à essayer de déréférencer self
.
Changer de
impl Bar {
fn get_foo(self) -> Box<Foo> {
self.foo
}
}
Est tout bon.
Donc....
- Pourquoi ne pas
&
dans lebar
struct travail? Je suis en supposant que j'ai à la boîte
structs avoir une set-disposition de la mémoire nous avons donc dire que c'est un pointeur
à un trait (que nous ne pouvons pas savoir comment grand que sera), mais pourquoi ne l'
compilateur de proposer quelque chose que l'habitude de compiler? - Pourquoi ne puis-je pas déréférencer
self
dansget_foo()
- Tous les exemples que j'ai vu utiliser le empruntésself
syntaxe? - Quelle est l'implication de la suppression de la
&
et seulement à l'aide deself
?
L'apprentissage de la Rouille qui est fascinant, mais la mémoire de la sécurité est à la fois fascinant et intimidant!
Code de la totalité de la compile:
trait Foo {
fn do_something(&self) -> f64;
}
struct Bar {
foo: Box<Foo>,
}
impl Bar {
fn get_foo(self) -> Box<Foo> {
let foo = self.foo;
foo.do_something();
foo
}
}
fn main() {}
Vous devez vous connecter pour publier un commentaire.
C'est le point délicat de trait des objets, vous devez être très explicite au sujet de qui est propriétaire de l'objet sous-jacent.
En effet, lorsque vous utilisez un trait de caractère comme un type, l'objet sous-jacent doivent être stockés quelque part, comme trait d'objets sont en fait des références à un objet la mise en œuvre de la trait. C'est pourquoi vous ne pouvez pas avoir un nu -
MyTrait
comme un type, il doit être une référence&MyTrait
ou une boîteBox<MyTrait>
.Avec des références
La première méthode que vous avez essayé a été a été avec une référence et le compilateur se sont plaints d'un manque de durée de vie de rédacteur de devis :
Le problème est, une référence n'est pas propriétaire de l'objet sous-jacent, et d'un autre objet ou la portée doit être propriétaire de quelque part: vous êtes seulement à l'emprunter. Et donc, le compilateur a besoin d'informations sur combien de temps cette référence sera valide: si l'objet sous-jacent a été détruit, votre Barre d'instance aurait une référence à la mémoire libérée, ce qui est interdit !
L'idée ici est d'ajouter la durée de vie:
Ce que vous êtes en train de dire au compilateur est : "Ma Barre d'objet ne peut pas survivre à la Foo de référence à l'intérieur". Vous devez spécifier la durée de vie deux fois : une fois pour la durée de vie de la référence, et une fois pour le trait de l'objet lui-même, parce que les traits peuvent être mises en œuvre pour les références, et si l'objet sous-jacent est une référence, vous devez indiquer sa vie.
Sur le cas particulier serait écrit:
Dans ce cas, le
'static
exige que l'objet sous-jacent doit être une véritable structure, ou un&'static
de référence, mais d'autres références ne seront pas autorisés.Aussi, pour construire votre objet, vous aurez à donner une référence à un autre objet, vous stockez vous-même.
Vous vous retrouvez avec quelque chose comme ceci :
Avec Des Boîtes De
Une Boîte contrairement propriétaire de son contenu, ainsi il vous permet d'attribuer la propriété de l'objet sous-jacent à votre Barre de struct. Pourtant, comme cet objet sous-jacent pourrait être une référence, vous devez spécifier une durée de vie ainsi :
Si vous savez que l'objet sous-jacent ne peut pas être une référence, vous pouvez également écrire:
et la durée de vie problème disparaît complètement.
La construction de l'objet est donc semblable, mais plus simple car vous n'avez pas besoin de stocker l'objet sous-jacent de vous-même, elle est gérée par la boîte :
Dans ce cas, le
'static
version :Avec le strict valeur
Pour répondre à votre dernière question :
Si une méthode a une définition comme ceci :
Cela signifie qu'il va consommer votre objet dans le processus, et après l'appel de
bar.unwrap()
, vous ne serez pas en mesure d'utiliserbar
plus.C'est un processus utilisé de manière générale pour redonner de la propriété des données de votre structure de la propriété. Vous allez rencontrer beaucoup de
unwrap()
fonctions de la bibliothèque standard.foo: &'a Foo
etfoo: Box<Foo>
. Ce qui explique ces changements?À la note de référence pour l'avenir: la syntaxe a changé à partir de
à
Par RFC 438