rust - How to access a vector multiple times within an 'Option'? -
how access vector within option without rust moving on first access?
fn maybe_push(v_option: option<&mut vec<usize>>) -> usize { let mut c = 0; if let some(v) = v_option { in 0..10 { v.push(i); c += i; } } else { in 0..10 { c += i; } } // second access, fails if let some(v) = v_option { in 10..20 { v.push(i); c += i; } } else { in 10..20 { c += i; } } return c; } fn main() { let mut v: vec<usize> = vec![]; println!("{}", maybe_push(some(&mut v))); println!("{}", maybe_push(none)); println!("{:?}", v); }
this gives error:
error[e0382]: use of partially moved value: `v_option` --> src/main.rs:16:22 | 4 | if let some(v) = v_option { | - value moved here ... 16 | if let some(v) = v_option { | ^^^^^^^^ value used here after move
using if let some(ref mut v) = v_option {
has been suggested fails too:
error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::some).0` mutable --> src/main.rs:4:21 | 4 | if let some(ref mut v) = v_option { | ^^^^^^^^^ error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::some).0` mutable --> src/main.rs:17:21 | 17 | if let some(ref mut v) = v_option { | ^^^^^^^^^
matching value moves value pattern variables. moving makes original value unusable, except simple objects implement copy
trait, such numbers. unlike pointers in c, mutable references not copyable, can seen in following example doesn't compile either:
let mut v = vec![1, 2, 3]; let rv = &mut v; // mutable reference v { // move rv r1, r1 becomes sole mutable reference v let r1 = rv; r1.push(4); } { let r2 = rv; // error: rv moved r1 r2.push(5); }
rust rejects above because enforces general rule prohibiting multiple mutable references object. despite particular snippet being safe, allowing multiple mutable references same object @ same time make easy write kind of unsafe programs rust explicitly designed prevent, e.g. contain data races in multithreaded code, or access data through invalidated iterator. assignment let r1 = rv
can move rv
reference r1
, disallowing let r2 = rv
statement refers moved variable rv
.
to fix code, must create separate references to reference. create 2 distinct mutable references original reference rather moving original mutable reference inner scope:
let mut v = vec![1, 2, 3]; let mut rv = &mut v; { // rr1 *new* mutable reference rv - no move performed let rr1 = &mut rv; rr1.push(4); } { // rr2 *separate* new mutable reference rv - no move let rr2 = &mut rv; rr2.push(5); }
the syntax of push
invocation same r1.push
, rr1.push
because rust's .
operator automatically dereference number of references.
to return example question, reference vec<usize>
in option
v
reference above, , matching using some(v)
pattern moves reference v
pattern variable.
to fix it, pattern must changed in above example, specify variable refers value reference. achieved using if let some(ref mut v)
syntax. above, rv
declaration had changed mutable, fix requires option
mutable. 2 changes, code compiles:
fn maybe_push(mut v_option: option<&mut vec<usize>>) -> usize { let mut c = 0; if let some(ref mut v) = v_option { in 0..10 { v.push(i); c += i; } } else { in 0..10 { c += i; } } if let some(ref mut v) = v_option { in 10..20 { v.push(i); c += i; } } else { in 10..20 { c += i; } } return c; } fn main() { let mut v: vec<usize> = vec![]; println!("{}", maybe_push(some(&mut v))); println!("{}", maybe_push(none)); println!("{:?}", v); }
another possibility use as_mut()
method return option content mutable reference previous content. conceptually equivalent change let r1 = rv
let rr1 = &mut rv
in first snippet, , allow use of if let some(v)
pattern, v
still reference mutable reference vector. requires v_option
declared mutable.
Comments
Post a Comment