borrow checker - How to alter two fields at once in a Rust struct? -


consider following simple example:

pub struct bar {     curr: vec<i32>,     prev: vec<i32>, }  pub fn main() {     let mut b = bar { curr: vec![1, 2, 3], prev: vec![2, 3, 4] };      foo(&mut b); }  pub fn foo(bar: &mut bar) {     let next = vec![3, 4, 5];      bar.prev = bar.curr;     bar.curr = next; } 

the use of vec doesn't matter; point bar has 2 fields don't implement copy. doesn't compile:

error[e0507]: cannot move out of borrowed content   --> derp.rs:15:16    | 15 |     bar.prev = bar.curr;    |                ^^^ cannot move out of borrowed content 

it's not hard see why: moving bar.curr without replacing immediately, have move bar itself, we're not allowed do, it's borrowed mutably, not owned.

however common use case (in case -- keeping last 2 outputs of function, example) , feel there must idiomatic rust use case. realize can gotten around using single tuple (curr, prev) , assigning @ once, (supposing function foo written long after struct bar has been in use) refactoring pretty frustrating.

assigning 2 values @ once doesn't seem legal: code (bar.prev, bar.curr) = (bar.curr, next) doesn't compile left side isn't legal left-hand-side value.

it interesting following code compiles:

pub struct bar {     curr: vec<i32>,     prev: vec<i32>, }  pub fn main() {     let b = bar { curr: vec![1, 2, 3], prev: vec![2, 3, 4] };      foo(b); }  pub fn foo(mut bar: bar) -> bar {     let next = vec![3, 4, 5];      bar.prev = bar.curr;     bar.curr = next;      bar } 

while line bar.prev = bar.curr seems require move privileges, doesn't seem use them, following line bar.curr = next shouldn't compile if bar has been moved.

additionally, if take bar.curr = next line out, no longer compiles (bar returned after being moved), seems compiler smart enough figure out how resolve issue (that fields end stably assigned), can't same task mutable pointers.

so guess (a) bug, (b) known bug, , (c) there workaround can still mutable pointers?

use std::mem::replace or std::mem::swap.

pub fn foo(bar: &mut bar) {     use std::mem;     let next = vec![3, 4, 5];     bar.prev = mem::replace(&mut bar.curr, next); } 

it interesting following code compiles [...]

this because own structure, compiler can safely break apart. can't when structure borrowed or behind kind of pointer. key question is: happens if panic half-way through modification (answer: it's possible code higher in call stack observe invalid value, , rust won't allow happen).

this isn't bug, it's how rust works.


Comments

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -