Rust to owned Example (Moved Value Tips)Learn ways to fix the moved value error by using to_owned or Arc references.
To owned. In Rust we must understand the concept of moved values, and how to prevent values from moving when not wanted. A program will not even compile with this kind of problem.
In this language, a value like a string can be moved into a Vector, loop, or function. To prevent moving, we can call to owned() or create Arc references.
Example program. This program shows how we might get into an error with moved values. We create the "shared" string and pass it to the push() function on a vector.
And The comment shows some code where we try to push the string to another vector. But this will not compile.
Info The string was moved into the "elements" vector, so we cannot use it in the "elements2" vector.
So To fix the compilation error in this program, we must avoid moving the string into the first vector.
Rust program that shows problem with moved value
fn main() { let shared = "bird".to_uppercase(); let mut elements = vec![]; elements.push(shared); // Value "shared" was moved here. // let mut elements2 = vec![]; // elements2.push(shared); // Cannot reuse the "shared" value here. println!("DONE"); }
Error text. The Rust compiler carefully explains the problem in the program. The string does not copy itself automatically, as it lacks the Copy trait.
So The string is moved into the first vector. But this causes the string to not be available for use in the second vector.
Moved value error:
error[E0382]: use of moved value: shared move occurs because shared has type String, which does not implement the Copy trait ... value moved here ... value used here after move
Example, to owned. We can copy the string into the first vector, which prevents it from moving there. We can use the "to owned" function to copy and transfer ownership.
Tip This Rust program compiles with no errors. But it causes the string to be copied, so it exists in 2 places.
Rust program that uses to owned function
fn main() { let shared = "bird".to_uppercase(); let mut elements = vec![]; elements.push(shared.to_owned()); // Copy into this vector, without moving. let mut elements2 = vec![]; elements2.push(shared); // Move the element here. println!("DONE"); }
Arc example. Suppose we want to share the same string in the 2 vectors. We can do this by creating an Arc with the string as an argument. Then we clone() the Arc instead of copying a string.
Info The Arc is an atomic reference count. This means is can be used across threads—an Rc is a single-threaded, faster version.
Note The type of the vectors is now an Arc. If the vectors were stored in a struct, or passed to a function, we would need to change the type.
Rust program that uses Arc to share string
use std::sync::Arc; fn main() { let shared = "bird".to_uppercase(); let arc = Arc::new(shared); let mut elements = vec![]; elements.push(arc.clone()); // Copy Arc into vector. let mut elements2 = vec![]; elements2.push(arc.clone()); println!("DONE: {}", elements[0]); }
Memory notes. Consider a short string—one with just 3 characters. This would be something we could copy to multiple vectors without any performance worries.
However For a long string, like 1000 characters, we would benefit from sharing the data and using Arc references to it.
A summary. For new Rust developers, it is easiest to just copy everything more than needed. Later, we can optimize out copies by adding Arcs to the data that is large enough to be a concern.
© 2007-2022 sam allen.
see site info on the changelog.