Short version: Remove the dereference and push(line.clone())
instead.
The why
Take the following code:
fn main() {
let mut foo = vec![1, 2, 3, 4, 5];
for num in foo {
println!("{}", num);
}
foo.push(6);
}
Playground
When running this code, the following error is raised:
error[E0382]: use of moved value: `foo`
--> src/main.rs:8:5
|
4 | for num in foo {
| --- value moved here
...
8 | foo.push(6);
| ^^^ value used here after move
|
= note: move occurs because `foo` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
This error rises because Rust for
loops take ownership of the iterator in question, specifically via the IntoIterator
trait. The for loop in the above code can be equivalently written as for num in foo.into_iter()
.
Note the signature of into_iter()
. It takes self
rather than &self
; in other words, ownership of the value is moved into the function, which creates an iterator for use in the for
loop, and the generated iterator is dropped at the end of the loop. Hence why the above code fails: We are attempting to use a variable which was "handed over" to something else. In other languages, the typical term used is that the value used for the loop is consumed.
Acknowledging this behavior gets us to the root of your problem, namely the "move" in cannot move out of borrowed content
. When you have a reference, like lines
(a reference to a Vec
), you have only that - a borrow. You do not have ownership of the object, and therefore you cannot give ownership of that object to something else, which could cause memory errors that Rust is designed to prevent. Dereferencing lines
effectively says "I want to give the original vector to this loop", which you can't do, since the original vector belongs to someone else.
Loosely speaking - and I may be wrong on this front, someone please correct me if I am - but dereferencing in Rust is, in most cases, only useful for modifying the object in the left-hand side of an assignment, since basically any use of a dereference in the right-hand side of an expression will try to move the item. For example:
fn main() {
let mut foo = vec![1, 2, 3, 4, 5];
println!("{:?}", foo);
{
let num_ref: &mut i32 = &mut foo[2]; // Take a reference to an item in the vec
*num_ref = 12; // Modify the item pointed to by num_ref
}
println!("{:?}", foo);
}
Playground
The above code will print:
[1, 2, 3, 4, 5]
[1, 2, 12, 4, 5]
The how
So the unfortunate truth is that there is no way to use the dereference in this case. But you're in luck - there's an easy way to solve your issue of type mismatch. The handy trait, Clone
, defines a function called clone()
that is expected to create an entirely new instance of the type, with the same values. Most basic types in Rust implement Clone
, including String
. So with a single function call, your type mismatch woes go away:
fn select_lines(pattern: &String, lines: &Vec<String>) -> Vec<String> {
let mut selected_lines: Vec<String> = Vec::new();
for line in lines {
if line.contains(pattern) {
// 'line.clone()' will create a new String for
// each line that contains the pattern, and
// place it into the vector.
selected_lines.push(line.clone());
}
}
selected_lines
}
Playground, with an example
clone()
is your friend, and you should get familiar with it, but be aware that it does require additional memory (up to double, if all the lines match), and that the lines placed into selected_lines
cannot be easily linked back to their counterparts in lines
. You shouldn't worry about the memory issue until you move out of experimentation and into production with very large datasets, but if the latter problem poses an issue, I'd like to point you to this alternative solution, which does edit the function signature in order to return references to the matching lines instead:
fn select_lines<'a>(pattern: &String, lines: &'a Vec<String>) -> Vec<&'a String> {
let mut selected_lines: Vec<&'a String> = Vec::new();
for line in lines {
if line.contains(pattern) {
selected_lines.push(&line);
}
}
selected_lines
}
This example includes Lifetimes, which is something you likely won't need to learn for a while, but you're free to examine this example as you wish!
Playground link, with an example, and some mutability edits.