rust - Preventing move semantics during pattern matching -


i have silly example here, demonstrate issue i'm running library , pattern matching.

struct person {     name: string,     age: i32,     choice: choices }  #[derive(debug)] enum choices {     good,     neutral,     evil }  fn find(p: person) {     match (p.choice, p.age) {         (choices::good, a) if < 80 => {             announce(p);         }         (_, a) if >= 80 => {             println!("you're old care.");         }         _ => {             println!("you're not nice!")         }     } }  fn announce(p: person) {     println!("your name {}. {:?}.", p.name, p.choice); }  fn main() {     let p = person {                 name: "bob".to_string(),                 age: 20,                 choice: choices::good             };     find(p); } 

now issue seems during pattern matching, move semantics kick in , take ownership on inner struct (thing) in person.

when go move person on next method, can't because it's been partially moved.

compiling match v0.1.0 (file:///home/jocull/documents/projects/rust/learn/match) src/main.rs:17:13: 17:14 error: use of partially moved value: `p` src/main.rs:17          announce(p);                                  ^ src/main.rs:15:9: 15:17 note: `p.choice` moved here because has type `choices`, non-copyable src/main.rs:15  match (p.choice, p.age) {                        ^~~~~~~~ error: aborting due previous error not compile `match`. 

my gut says need rust stop moving value using reference or borrow of kind. in case could change method signature borrow, libraries aren't able that. (i trying deal hyper in case...)

is there way match use references during matching instead of moving values? thank you!

why?

when make tuple

(p.choice, p.age) 

you memcpy both p.choice , p.age person.

it's ok p.age because it's copy type - can continue using old value after memcpying it.

p.choices of type choices not copy. means memcpy treated "move", old value not usable. means p in invalid state, can't call announce on it.

solution #1

since choices trivial enum, can #[derive(copy, clone)]. means allowed continue using old p.choices.

if can safely make choices clone, you'd have clone in match instead.

solution #2

you can take p.choices reference:

match (&p.choice, p.age) {     (&choices::good, a) if < 80 => {         announce(p);     }     ... } 

this works because &choices::good exact match borrow can relinquished. if had instead

match (&p.choice, p.age) {     (&x, a) if < 80 => {         announce(p);     }     ... } 

the borrow still active , move when calling announce(p) fail - move invalidate active borrowed variable.

notes

you're doing awful lot of moving here - passing few references lot more flexible! there's no reason announce consume person - needs @ bit. taking value when take reference advisable small copy types.

note having announce take reference means match allowed holding on references inside p, makes more applicable.

to_string use non-string objects. into , to_owned faster , into lot shorter.

struct person {     name: string,     age: i32,     choice: choices }  #[derive(copy, clone, debug)] enum choices {     good,     neutral,     evil }  fn find(p: &person) {     match (p.choice, p.age) {         (choices::good, a) if < 80 => {             announce(p);         }         (_, a) if >= 80 => {             println!("you're old care.");         }         _ => {             println!("you're not nice!")         }     } }  fn announce(p: &person) {     println!("your name {}. {:?}.", p.name, p.choice); }  fn main() {     let p = person {         name: "bob".into(),         age: 20,         choice: choices::good     };      find(&p); } 

Comments

Popular posts from this blog

angularjs - ADAL JS Angular- WebAPI add a new role claim to the token -

php - CakePHP HttpSockets send array of paramms -

node.js - Using Node without global install -