How to rotate a linked list in Rust? - rust

I came across a leetcode example https://leetcode.com/problems/rotate-list/ and wanted to implement it in Rust but I keep moving out of my variables. For instance if I use head to track down the end of the list I cannot move its value to the last next because it is already moved out of the variable. How should I think to avoid this kind of problems?
And this is my attempt in rust
// Definition for singly-linked list.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode { next: None, val }
}
}
pub fn rotate_right(head: Option<Box<ListNode>>, k: i32) -> Option<Box<ListNode>> {
if k == 0 {
return head;
}
let mut len = 0;
let mut curr = &head;
while let Some(n) = curr {
curr = &n.next;
len += 1;
}
drop(curr);
let newk = len - ( k % len);
println!("Rotate {} right is {} mod {}",k,newk,len);
let mut node = head.as_ref();
for _i in 0..newk {
if let Some(n) = node {
node = n.next.as_ref();
}else {
println!("Unexpected asswer fail");
}
}
let mut newhead = None ;// node.unwrap().next; // node will be last and newhead will be first.
if let Some(mut n) = node{ // node should have a value here
newhead = n.next;
n.next = None
}
drop(node);
let node = newhead;
if let Some(c) = node{
let mut curr = c;
while let Some(next) = curr.next {
curr = next;
}
curr.next = head;
newhead
}else{
println! ("Todo handle this corner case");
None
}
}
But this yields errors about moving and use of borrowed references.
error[E0507]: cannot move out of `n.next` which is behind a shared reference
--> src/main.rs:99:23
|
99 | newhead = n.next;
| ^^^^^^
| |
| move occurs because `n.next` has type `Option<Box<ListNode>>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `n.next.as_ref()`
error[E0594]: cannot assign to `n.next` which is behind a `&` reference
--> src/main.rs:100:13
|
98 | if let Some(mut n) = node{ // node should have a value here
| ----- help: consider changing this to be a mutable reference: `&mut Box<ListNode>`
99 | newhead = n.next;
100 | n.next = None
| ^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
error[E0382]: use of moved value: `newhead`
--> src/main.rs:111:13
|
97 | let mut newhead = None ;// node.unwrap().next; // node will be last and newhead will be first.
| ----------- move occurs because `newhead` has type `Option<Box<ListNode>>`, which does not implement the `Copy` trait
...
104 | let node = newhead;
| ------- value moved here
...
111 | newhead
| ^^^^^^^ value used here after move
Finlay this is reference code in c of what I intended it to look like:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* rotateRight(struct ListNode* head, int k){
struct ListNode* node = head;
int len = 1;
if (k == 0 || !head){
return head;
}
while (node->next){
node = node->next;
len++;
}
int newk = len - (k % len) -1;
node = head;
while (newk--){
if (node->next) {
node = node->next;
}
}
if ( !node->next) {
return head; // do not move anything
}
struct ListNode* newhead = node->next; // node will be last and newhead will be first.
struct ListNode* n = node->next;
node->next = 0;
node = n;
while (node->next != 0) {
node = node->next;
}
node->next = head;
return newhead;
}
So my question is what technique can be used to avoid this move use trap?

I'd like to preface this post by saying that this type of Linked List in Rust is not a particularly good representation. Unfortunately, safe Rust's ownership model makes reference chain structures such as Linked Lists problematic and hard to reason about for any more than simple operations, despite Linked Lists being very simple in other languages. While for beginners, simple but inefficient implementations of simple concepts are often important and useful, I would also like to emphasize that the safe Rust "sentinel model" for trees and linked lists also has a heavy performance cost. Learning Rust With Entirely Too Many Linked Lists is the de facto book for learning how to properly deal with these structures, and I recommend it to all beginners and intermediate Rust programmers who haven't worked through it (or at least skimmed it).
However, this particular operation is possible on sentinel model singly linked lists in purely safe Rust. The whole version of the code I'm about to present is available on the Playground, which includes some things like test cases and an iterator implementation I'll be glossing over (since it doesn't get to the core of the problem and is only used in test cases and to derive the entire size of the Linked List). I also won't be presenting the ListNode struct or the new function, since they are in the question itself. Note that I also took some design liberties (instead of a free function, I made rotate_right and rotate_left member functions, you can freely convert but this is more Rusty design).
The "obvious' implementation here is to drain the entire list and reconstruct it. This is a perfectly good solution! However it's likely inefficient (it can be more or less inefficient depending on whether you totally destroy the nodes or not). Instead we're going to be doing what you largely do in other languages: only breaking the link and then reassigning the pointers at the boundaries. In fact, once you break it down into these two steps, the problem becomes much easier! All that's required is knowledge about Rust's mutable borrowing semantics, and how to overcome the pesky requirement that references always have a definite value and cannot be moved out of.
1. Breaking the Link: mutable reference uniqueness & memory integrity
/// Splits the list at a given index, returning the new split off tail.
/// Self remains unmodified.
/// The list is zero indexed, so,
/// for instance, a value of 2 in the list [1,2,3,4,5]
/// will cause self to be [1,2,3] and the return value to be
/// Some([4,5]). I.E. the link is "broken" AT index 2.
///
/// If there's nothing to split off, `None` is returned.
fn split_at(&mut self, n: usize) -> Option<Self> {
use std::mem;
let mut split = Some(self);
for _ in 0..n {
if let Some(node) = split.map(|v| v.next.as_deref_mut()) {
split = node;
} else {
return None;
}
}
match split {
Some(node) => {
let mut new_head = None;
mem::swap(&mut new_head, &mut node.next);
new_head.map(|v| *v)
}
None => None
}
}
The logic is straightforward (if you've broken off a list in any other language it's the exact same algorithm). The important thing for Rust is the ownership system and the mem::swap function. Rust ensures two things that are problematic here:
You're not mutably borrowing the same thing twice.
No piece of memory is invalid, even temporarily (particularly in self).
For 1., we use the code
if let Some(node) = split.map(|v| v.next.as_deref_mut()) {
split = node;
}
What this does is simply advances the pointer, making sure to immediately "forget" our current mutable pointer, and never do anything that directly causes "self" to be used at the same time as "node". (Note that if you tried this in an earlier version of Rust, I don't believe this was possible before Non-Lexical Lifetimes (NLLs), I think it would both alias self and node under the old rules). The map is simply to allow us to reassign to split by "reborrowing" the inner Box as an actual reference, so we can recycle the seed variable we start as self (since you can't reassign self in this way).
For solving 2. we use:
match split {
Some(node) => {
let mut new_head = None;
mem::swap(&mut new_head, &mut node.next);
new_head.map(|v| *v)
}
None => None
}
The key here is the mem::swap line. Without this Rust will complain about you moving node.next. Safe Rust requires you to ensure there is always a value in every variable. The only exception is if you're permanently destroying a value, which doesn't work on references. I think there's some QOL work on the compiler at the moment to allow you to move out of a mutable reference if you immediately put something in its place and the compiler can prove there will be no panic or return between these operations (i.e. memory cannot become corrupted during a stack unwind), but as of Rust 1.47 this is not available.
2. Stitching the list back together: memory integrity
/// Attaches the linked list `new_tail` to the end
/// of `self`. For instance
/// `[1,2,3]` and `[4,5]` will make self a list containing
/// `[1,2,3,4,5]`.
fn extend_from_list(&mut self, new_tail: ListNode) {
let mut tail = self;
while tail.next.is_some() {
tail = tail.next.as_deref_mut().unwrap();
}
tail.next = Some(Box::new(new_tail))
}
This method isn't too complicated, it just assigns the next reference to the head node of the passed in list. If you've written a function to attach a new node it's functionally the same. Again, the key is that we advance the pointer to the end, being very careful we never allow a mutable reference to alias, which allows us to appease the Borrow Checker.
From there, we can finish up!
/// Rotates the list `k` elements left. So
/// `[1,2,3]` rotated 2 left is `[3,1,2]`.
///
/// The function handles rotating an arbitrary number of steps
/// (i.e. rotating a size 3 list by 5 is the same as rotating by 2).
fn rotate_left(&mut self, k: usize) {
use std::mem;
let k = k % self.iter().count();
if k == 0 {
return;
}
let k = k-1;
if let Some(mut new_head) = self.split_at(k) {
mem::swap(self, &mut new_head);
let new_tail = new_head;
self.extend_from_list(new_tail);
} else {
unreachable!("We should handle this with the mod!")
}
}
/// Rotates the list `k` elements right. So
/// `[1,2,3]` rotated 2 right is `[2,3,1]`.
///
/// The function handles rotating an arbitrary number of steps
/// (i.e. rotating a size 3 list by 5 is the same as rotating by 2).
fn rotate_right(&mut self, k: usize) {
self.rotate_left(self.iter().count() - k)
}
Rotating left is conceptually easiest, since it's just splitting a list at the given index (k-1 because to rotate k places we need to break the link after counting one fewer indices). Again, we need to make use of mem::swap, the only tricky thing about this code, because the part we split off is the new head and Rust won't let us use temp variables due to the memory integrity guarantee.
Also, it turns out rotating right k places is just rotating left size-k places, and is much easier to conceptualize that way.
This is all somewhat inefficient though because we're marching to the end of the list each time (particularly for the list fusion), because we're not holding onto the tail pointer and instead re-iterating. I'm fairly certain you can fix this, but it may be easier to make it one large function instead of sub-functions, since returning a downstream tail pointer would require some lifetime flagging. I think if you want to take a next step (besides the Linked List book, which is probably a better use of your time), it would be good to see if you can preserve the tail pointer to eliminate the constant marching down the list.

Related

rust deferencing and mutable variables

I am very new to Rust, so forgive me if the question is obvious.
How does rust dereferencing work? Please see below example.
I am reading a book about rust and I found the following example with an explanation regarding the use of & in the vector variable of numbers[1...]. It says that it is used to "borrow its elements for the loop". Can anyone explain what that means in terms of memory and what is actual difference vs not using & sign?
The second question was regarding *m operator, where it says "it lets m borrow each element in succession, the * operator deferences m, yielding the value it refers to". Does it mean that *m will exhaust the variable and will no longer be available?
fn main() {
let mut numbers = Vec::new();
for arg in env::args().skip(1) {
numbers.push(u64::from_str(&arg)
.expect("error parsing argument"));
}
if numbers.len() == 0 {
eprintln!("Usage: gcd NUMBER ...");
std::process::exit(1);
}
let mut d = numbers[0];
for m in &numbers[1..] {
d = gcd(d, *m);
}
println!("The greatest common divisor of {:?} is {}",
numbers, d);
}
fn gcd(mut n: u64, mut m: u64) -> u64 {
assert!(n != 0 && m != 0);
while m != 0 {
if m < n {
let t = m;
m = n;
n = t;
}
Let me recommend the "References and Borrowing" section in the Rust book. It has a lot of good information about this topic.
First, the easy question:
Does it mean that *m will exhaust the variable and will no longer be available?
The * operator indeed dereferences until you are at the actual object. For example, look at the following code. I use String here because it isn't Copy:
fn main() {
let x = String::from("aaa.");
let x_ref = &x;
*x_ref;
}
error[E0507]: cannot move out of `*x_ref` which is behind a shared reference
--> src/main.rs:4:5
|
4 | *x_ref;
| ^^^^^^ move occurs because `*x_ref` has type `String`, which does not implement the `Copy` trait
Note that we don't do anything with *x_ref; the act of dereferencing alone is already enough for the compiler to complain. Dereferencing would indeed consume the object, but you can't move an object out of a reference, so the compiler complains.
Note that in your loop, the *m works without a problem. That's because u64 implements Copy, which means anything that would move the u64 away instead performs a copy.
The other question is a little harder:
It says that it is used to "borrow its elements for the loop".
Yes and no; loops are actually a bit unintuitive to be honest. It's more complicated behind the scenes than the beginner tutorials reveal, and explaining it in detail would be too much for this post.
Just as a quick teaser: &numbers[1..] actually creates a &[u64] slice into the numbers array. for then calls into_iter() on that slice, which consumes the slice and returns an iterator that produces &u64 elements. The for loop then uses this iterator to loop.
What might probably help you most is if you read the section about slices in the Rust book. That should give you an initial idea, and if you still struggle with some details, you can open a new, more specific question on SO.

Mutable and immutable borrow problems with Vec<Vec<i32>> [duplicate]

This question already has answers here:
How to get mutable references to two array elements at the same time?
(8 answers)
Closed 8 months ago.
I'm solving a problem from Leetcode and encountered the fact that Rust won't let me execute it efficiently. What am I doing wrong? I know about the book article about references and borrowing and would like to know how to solve this problem despite the peculiarities of the language.
I am trying to create one reference for a vec that should change and another for a vec that will not change. Rust won't let me do that. The program works, but only when using .clone(), which will be very slow and not necessary (last_row does not change anywhere, only the values are derived from there).
Here is the working code:
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let last_row = & triangle[i+1].clone();
let current_row = &mut triangle[i];
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
As you can see, I used .clone() to fix the borrow checker errors that show up when you try to write a program using references:
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let current_row = &mut triangle[i];
let last_row = &triangle[i+1];
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
Terminal:
error[E0502]: cannot borrow `triangle` as immutable because it is also borrowed as mutable
--> src\main.rs:6:25
|
5 | let current_row = &mut triangle[i];
| -------- mutable borrow occurs here
6 | let last_row = &triangle[i+1];
| ^^^^^^^^ immutable borrow occurs here
7 | for j in 0..current_row.len() {
| ----------------- mutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
However, when trying to write a program poorly everything works without any problems:
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
for j in 0..triangle[i].len() {
triangle[i][j] = cmp::min(triangle[i+1][j], triangle[i+1][j+1]) + triangle[i][j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
You can accomplish this via the split_at_mut() method, which comes from the primitive slice type (which Vec auto-derefs to). This method allows you to safely take a mutable slice and split it into two mutable slices at a given index, since it's guaranteed that the two slices won't overlap. (Note this is zero-copy, as slices are just fat pointers borrowing an existing contiguous sequence.)
The two slices then are independent for the purposes of borrow checking, so you can borrow mutably from both slices at the same time (or, in your case, mutably from one and immutably from the other).
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let (left, right) = triangle.split_at_mut(i + 1);
let current_row = left.last_mut().unwrap();
let last_row = right.first().unwrap();
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
Yes, that's the thing with Rust -- you have to code in a way that the compiler can tell it is safe. Sometimes that requires a bit of thought, but often in the end you have code that is cleaner than you would have written otherwise.
Imagine having a function that could walk through items two at a time, calling a function you specify on them, with the first being immutable, and the second being mutable. Call it pairs_mut, and calling it with function f on a,b,c,d it would result in calls to f(&a, &mut b), f(&b, &mut c), and f(&c, &mut d). A non-generic version is not that hard to write. I am hesitant to put the code here because you are trying to learn from the exercise.
NOTE: I suspect that such a facility (or perhaps something more general) exists somewhere in the Rust ecosystem, but I have looked in Iterator and the itertools crate and didn't find anything. If you know of an existing facility like this, please share a link in a comment. Otherwise perhaps I should try to get something added to itertools.
Now given pairs_mut, I hope you can see that minimum_total could run it on triangle.rev() and do that bit of dynamic programming to come up with the minimum sum. Let me know if you want me to put some actual code here, but I encourage you to try it yourself first.

Creating struct with values from function parameter Vec<String>and returning Vec<struct> to caller

The purpose of my program is to read questions/answers from a file (line by line), and create several structs from it, put into a Vec for further processing.
I have a rather long piece of code, which I tried to separate into several functions (full version on Playground; hopefully is valid link).
I suppose I'm not understanding a lot about borrowing, lifetimes and other things. Apart from that, the given examples from all around I've seen, I'm not able to adapt to my given problems.
Tryigin to remodel my struct fields from &str to String didn't change anything. As it was with creating Vec<Question> within get_question_list.
Function of concern is as follows:
fn get_question_list<'a>(mut questions: Vec<Question<'a>>, lines: Vec<String>) -> Vec<Question<'a>> {
let count = lines.len();
for i in (0..count).step_by(2) {
let q: &str = lines.get(i).unwrap();
let a: &str = lines.get(i + 1).unwrap();
questions.push(Question::new(q, a));
}
questions
}
This code fails with the compiler as following (excerpt):
error[E0597]: `lines` does not live long enough
--> src/main.rs:126:23
|
119 | fn get_question_list<'a>(mut questions: Vec<Question<'a>>, lines: Vec<String>) -> Vec<Question<'a>> {
| -- lifetime `'a` defined here
...
126 | let a: &str = lines.get(i + 1).unwrap();
| ^^^^^ borrowed value does not live long enough
127 |
128 | questions.push(Question::new(q, a));
| ----------------------------------- argument requires that `lines` is borrowed for `'a`
...
163 | }
| - `lines` dropped here while still borrowed
Call to get_question_list is around:
let lines: Vec<String> = content.split("\n").map(|s| s.to_string()).collect();
let counter = lines.len();
if counter % 2 != 0 {
return Err("Found lines in quiz file are not even (one question or answer is missing.).");
}
questions = get_question_list(questions, lines);
Ok(questions)
The issue is that your Questions are supposed to borrow something (hence the lifetime annotation), but lines gets moved into the function, so when you create a new question from a line, it's borrowing function-local data, which is going to be destroyed at the end of the function. As a consequence, the questions you're creating can't escape the function creating them.
Now what you could do is not move the lines into the function: lines: &[String] would have the lines be owned by the caller, which would "fix" get_question_list.
However the exact same problem exists in read_questions_from_file, and there it can not be resolved: the lines are read from a file, and thus are necessarily local to the function (unless you move the lines-reading to main and read_questions_from_file only borrows them as well).
Therefore the simplest proper fix is to change Question to own its data:
struct Question {
question: String,
answer: String
}
This way the question itself keeps its data alive, and the issue goes away.
We can improve things further though, I think:
First, we can strip out the entire mess around newlines by using String::lines, it will handle cross-platform linebreaks, and will strip them.
It also seems rather odd that get_question_list takes a vector by value only to append to it and immediately return it. A more intuitive interface would be to either:
take the "output vector" by &mut so the caller can pre-size or reuse it across multiple loads, which doesn't really seem useful in this case
or create the output vector internally, which seems like the most sensible case here
Here is what I would consider a more pleasing version: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c0d440d67654b92c75d136eba2bba0c1
fn read_questions_from_file(filename: &str) -> Result<Vec<Question>, Box<dyn Error>> {
let file_content = read_file(filename)?;
let lines: Vec<_> = file_content.lines().collect();
if lines.len() % 2 != 0 {
return Err(Box::new(OddLines));
}
let mut questions = Vec::with_capacity(lines.len() / 2);
for chunk in lines.chunks(2) {
if let [q, a] = chunk {
questions.push(Question::new(q.to_string(), a.to_string()))
} else {
unreachable!("Odd lines should already have been checked");
}
}
Ok(questions)
}
Note that I inlined / removed get_question_list as I don't think it pulls its weight at this point, and it's both trivial and very specific.
Here is a variant which works similarly but with different tradeoffs: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3b8f95aef5bcae904545617749086dbc
fn read_questions_from_file(filename: &str) -> Result<Vec<Question>, Box<dyn Error>> {
let file_content = read_file(filename)?;
let mut lines = file_content.lines();
let mut questions = Vec::new();
while let Some(q) = lines.next() {
let a = lines.next().ok_or(OddLines)?;
questions.push(Question::new(q.to_string(), a.to_string()));
}
Ok(questions)
}
it avoids collecting the lines to a Vec, but as a result has to process the file to the end before it knows that said file is suitable, and it can't preallocate Questions.
At this point, because we do not care for lines being a Vec anymore, we could operate on a BufRead and strip out read_file as well:
fn read_questions_from_file(filename: &str) -> Result<Vec<Question>, Box<dyn Error>> {
let file_content = BufReader::new(File::open(filename)?);
let mut lines = file_content.lines();
let mut questions = Vec::new();
while let Some(q) = lines.next() {
let a = lines.next().ok_or(OddLines)?;
questions.push(Question::new(q?, a?));
}
Ok(questions)
}
The extra ? are because while str::Lines yields &str, io::Lines yields Result<String, io::Error>: IO errors are reported lazily when a read is attempted, meaning every line-read could report a failure if read_to_string would have failed.
OTOH since io::Lines returns a Result<String, ...> we can use q and a directly without needing to convert them to String.

Is it possible to map a function over a Vec without allocating a new Vec?

I have the following:
enum SomeType {
VariantA(String),
VariantB(String, i32),
}
fn transform(x: SomeType) -> SomeType {
// very complicated transformation, reusing parts of x in order to produce result:
match x {
SomeType::VariantA(s) => SomeType::VariantB(s, 0),
SomeType::VariantB(s, i) => SomeType::VariantB(s, 2 * i),
}
}
fn main() {
let mut data = vec![
SomeType::VariantA("hello".to_string()),
SomeType::VariantA("bye".to_string()),
SomeType::VariantB("asdf".to_string(), 34),
];
}
I would now like to call transform on each element of data and store the resulting value back in data. I could do something like data.into_iter().map(transform).collect(), but this will allocate a new Vec. Is there a way to do this in-place, reusing the allocated memory of data? There once was Vec::map_in_place in Rust but it has been removed some time ago.
As a work-around, I've added a Dummy variant to SomeType and then do the following:
for x in &mut data {
let original = ::std::mem::replace(x, SomeType::Dummy);
*x = transform(original);
}
This does not feel right, and I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop. Is there a better way of doing this?
Your first problem is not map, it's transform.
transform takes ownership of its argument, while Vec has ownership of its arguments. Either one has to give, and poking a hole in the Vec would be a bad idea: what if transform panics?
The best fix, thus, is to change the signature of transform to:
fn transform(x: &mut SomeType) { ... }
then you can just do:
for x in &mut data { transform(x) }
Other solutions will be clunky, as they will need to deal with the fact that transform might panic.
No, it is not possible in general because the size of each element might change as the mapping is performed (fn transform(u8) -> u32).
Even when the sizes are the same, it's non-trivial.
In this case, you don't need to create a Dummy variant because creating an empty String is cheap; only 3 pointer-sized values and no heap allocation:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
let old = std::mem::replace(self, VariantA(String::new()));
// Note this line for the detailed explanation
*self = match old {
VariantA(s) => VariantB(s, 0),
VariantB(s, i) => VariantB(s, 2 * i),
};
}
}
for x in &mut data {
x.transform();
}
An alternate implementation that just replaces the String:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
*self = match self {
VariantA(s) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 0)
}
VariantB(s, i) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 2 * *i)
}
};
}
}
In general, yes, you have to create some dummy value to do this generically and with safe code. Many times, you can wrap your whole element in Option and call Option::take to achieve the same effect .
See also:
Change enum variant while moving the field to the new variant
Why is it so complicated?
See this proposed and now-closed RFC for lots of related discussion. My understanding of that RFC (and the complexities behind it) is that there's an time period where your value would have an undefined value, which is not safe. If a panic were to happen at that exact second, then when your value is dropped, you might trigger undefined behavior, a bad thing.
If your code were to panic at the commented line, then the value of self is a concrete, known value. If it were some unknown value, dropping that string would try to drop that unknown value, and we are back in C. This is the purpose of the Dummy value - to always have a known-good value stored.
You even hinted at this (emphasis mine):
I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop
That "should" is the problem. During a panic, that dummy value is visible.
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
Temporarily move out of borrowed content
How do I move out of a struct field that is an Option?
The now-removed implementation of Vec::map_in_place spans almost 175 lines of code, most of having to deal with unsafe code and reasoning why it is actually safe! Some crates have re-implemented this concept and attempted to make it safe; you can see an example in Sebastian Redl's answer.
You can write a map_in_place in terms of the take_mut or replace_with crates:
fn map_in_place<T, F>(v: &mut [T], f: F)
where
F: Fn(T) -> T,
{
for e in v {
take_mut::take(e, f);
}
}
However, if this panics in the supplied function, the program aborts completely; you cannot recover from the panic.
Alternatively, you could supply a placeholder element that sits in the empty spot while the inner function executes:
use std::mem;
fn map_in_place_with_placeholder<T, F>(v: &mut [T], f: F, mut placeholder: T)
where
F: Fn(T) -> T,
{
for e in v {
let mut tmp = mem::replace(e, placeholder);
tmp = f(tmp);
placeholder = mem::replace(e, tmp);
}
}
If this panics, the placeholder you supplied will sit in the panicked slot.
Finally, you could produce the placeholder on-demand; basically replace take_mut::take with take_mut::take_or_recover in the first version.

What do I have to do to solve a "use of moved value" error?

I'm trying to compute the 10,001st prime in Rust (Project Euler 7), and as a part of this, my method to check whether or not an integer is prime references a vector:
fn main() {
let mut count: u32 = 1;
let mut num: u64 = 1;
let mut primes: Vec<u64> = Vec::new();
primes.push(2);
while count < 10001 {
num += 2;
if vectorIsPrime(num, primes) {
count += 1;
primes.push(num);
}
}
}
fn vectorIsPrime(num: u64, p: Vec<u64>) -> bool {
for i in p {
if num > i && num % i != 0 {
return false;
}
}
true
}
When I try to reference the vector, I get the following error:
error[E0382]: use of moved value: `primes`
--> src/main.rs:9:31
|
9 | if vectorIsPrime(num, primes) {
| ^^^^^^ value moved here, in previous iteration of loop
|
= note: move occurs because `primes` has type `std::vec::Vec<u64>`, which does not implement the `Copy` trait
What do I have to do to primes in order to be able to access it within the vectorIsPrime function?
With the current definition of your function vectorIsPrime(), the function specifies that it requires ownership of the parameter because you pass it by value.
When a function requires a parameter by value, the compiler will check if the value can be copied by checking if it implements the trait Copy.
If it does, the value is copied (with a memcpy) and given to the function, and you can still continue to use your original value.
If it doesn't, then the value is moved to the given function, and the caller cannot use it afterwards
That is the meaning of the error message you have.
However, most functions do not require ownership of the parameters: they can work on "borrowed references", which means they do not actually own the value (and cannot for example put it in a container or destroy it).
fn main() {
let mut count: u32 = 1;
let mut num: u64 = 1;
let mut primes: Vec<u64> = Vec::new();
primes.push(2);
while count < 10001 {
num += 2;
if vector_is_prime(num, &primes) {
count += 1;
primes.push(num);
}
}
}
fn vector_is_prime(num: u64, p: &[u64]) -> bool {
for &i in p {
if num > i && num % i != 0 {
return false;
}
}
true
}
The function vector_is_prime() now specifies that it only needs a slice, i.e. a borrowed pointer to an array (including its size) that you can obtain from a vector using the borrow operator &.
For more information about ownership, I invite you to read the part of the book dealing with ownership.
Rust is, as I would say, a “value-oriented” language. This means that if you define primes like this
let primes: Vec<u64> = …
it is not a reference to a vector. It is practically a variable that stores a value of type Vec<u64> just like any u64 variable stores a u64 value. This means that if you pass it to a function defined like this
fn vec_is_prime(num: u64, vec: Vec<u64>) -> bool { … }
the function will get its own u64 value and its own Vec<u64> value.
The difference between u64 and Vec<u64> however is that a u64 value can be easily copied to another place while a Vec<u64> value can only move to another place easily. If you want to give the vec_is_prime function its own Vec<u64> value while keeping one for yourself in main, you have to duplicate it, somehow. That's what's clone() is for. The reason you have to be explicit here is because this operation is not cheap. That's one nice thing about Rust: It's not hard to spot expensive operations. So, you could call the function like this
if vec_is_prime(num, primes.clone()) { …
but that's not really what you want, actually. The function does not need its own a Vec<64> value. It just needs to borrow it for a short while. Borrowing is much more efficient and applicable in this case:
fn vec_is_prime(num: u64, vec: &Vec<u64>) -> bool { …
Invoking it now requires the “borrowing operator”:
if vec_is_prime(num, &primes) { …
Much better. But we can still improve it. If a function wants to borrow a Vec<T> just for the purpose of reading it, it's better to take a &[T] instead:
fn vec_is_prime(num: u64, vec: &[u64]) -> bool { …
It's just more general. Now, you can lend a certain portion of a Vec to the function or something else entirely (not necessarily a Vec, as long as this something stores its values consecutively in memory, like a static lookup table). What's also nice is that due to coersion rules you don't need to alter anything at the call site. You can still call this function with &primes as argument.
For String and &str the situation is the same. String is for storing string values in the sense that a variable of this type owns that value. &str is for borrowing them.
You move value of primes to the function vectorIsPrime (BTW Rust use snake_case by convention). You have other options, but the best one is to borrow vector instead of moving it:
fn vector_is_prime(num: u64, p: &Vec<u64>) -> bool { … }
And then passing reference to it:
vector_is_prime(num, &primes)

Resources