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
Post a Comment