Je ne comprends pas l'erreur cannot move out of borrowed content
. Je l'ai reçu plusieurs fois et je l'ai toujours résolu, mais je n'ai jamais compris pourquoi.
Par exemple:
for line in self.xslg_file.iter() {
self.buffer.clear();
for current_char in line.into_bytes().iter() {
self.buffer.Push(*current_char as char);
}
println!("{}", line);
}
produit l'erreur:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:31:33
|
31 | for current_char in line.into_bytes().iter() {
| ^^^^ cannot move out of borrowed content
Dans les nouvelles versions de Rust, l'erreur est
error[E0507]: cannot move out of `*line` which is behind a shared reference
--> src/main.rs:31:33
|
31 | for current_char in line.into_bytes().iter() {
| ^^^^ move occurs because `*line` has type `std::string::String`, which does not implement the `Copy` trait
Je l'ai résolu en clonant line
:
for current_char in line.clone().into_bytes().iter() {
Je ne comprends pas l'erreur même après avoir lu d'autres articles tels que:
Quelle est l'origine de ce genre d'erreur?
Regardons la signature pour into_bytes
:
_fn into_bytes(self) -> Vec<u8>
_
Cela prend self
, pas une référence à self (_&self
_). Cela signifie que self
sera consommé et ne sera plus disponible après l'appel. À sa place, vous obtenez un _Vec<u8>
_. Le préfixe _into_
_ est un moyen courant de désigner des méthodes comme celle-ci.
Je ne sais pas exactement ce que retourne votre méthode iter()
, mais je suppose que c'est un itérateur sur _&String
_, c'est-à-dire qu'il renvoie des références à String
mais ne vous donne pas la propriété d'eux. Cela signifie que vous ne pouvez pas appeler une méthode qui consomme la valeur .
Comme vous l'avez constaté, une solution consiste à utiliser clone
. Cela crée un objet en double que vous possédez et que vous pouvez appeler _into_bytes
_ on. Comme d'autres intervenants le mentionnent, vous pouvez également utiliser as_bytes
qui prend _&self
_, de sorte que cela fonctionnera avec une valeur empruntée. Lequel vous devriez utiliser dépend de votre objectif final pour ce que vous faites avec le pointeur.
Dans l’ensemble, tout cela a à voir avec la notion de propriété . Certaines opérations dépendent de la possession de l'élément, et d'autres opérations peuvent se permettre d'emprunter l'objet (peut-être de manière mutuelle). Une référence (_&foo
_) n'accorde pas la propriété, il s'agit simplement d'un emprunt.
Pourquoi est-il intéressant d'utiliser
self
au lieu de _&self
_ dans les arguments d'une fonction?
Le transfert de propriété est un concept utile en général - quand j'en ai fini avec quelque chose, quelqu'un d'autre peut l'avoir. À Rust, c'est un moyen d'être plus efficace. Je peux éviter d'allouer une copie, de vous en donner une, puis de jeter ma copie. La propriété est également l’état le plus permissif; si je possède un objet, je peux en faire ce que je veux.
Voici le code que j'ai créé pour tester:
_struct IteratorOfStringReference<'a>(&'a String);
impl<'a> Iterator for IteratorOfStringReference<'a> {
type Item = &'a String;
fn next(&mut self) -> Option<Self::Item> {
None
}
}
struct FileLikeThing {
string: String,
}
impl FileLikeThing {
fn iter(&self) -> IteratorOfStringReference {
IteratorOfStringReference(&self.string)
}
}
struct Dummy {
xslg_file: FileLikeThing,
buffer: String,
}
impl Dummy {
fn dummy(&mut self) {
for line in self.xslg_file.iter() {
self.buffer.clear();
for current_char in line.into_bytes().iter() {
self.buffer.Push(*current_char as char);
}
println!("{}", line);
}
}
}
fn main() {}
_