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?
ListNodeto your code snippet.