Match again with different variables, how to avoid partial move

Consider this code:

fn main() {}

fn takes_value(v: Value) {
    match v {
        Value::Number { key, .. } | Value::Text { key, .. } => {
            // A bunch of code that is common to both Number and Text Values
            println!("Key is: {}", key);
            consume_string(key);

            match v {
                Value::Number { number, .. } => {
                    println!("The number is: {}", number);
                    consume_float(number);
                }
                Value::Text { text, .. } => {
                    println!("The text is: {}", text);
                    consume_string(text);
                }
            }
        }
    }
}

fn consume_string(_: String) {}
fn consume_float(_: f64) {}

enum Value {
    Number { key: String, number: f64 },
    Text { key: String, text: String },
}

Playground

This doesn't compile:

error[E0382]: use of moved value: `v`
  --> src/main.rs:10:19
   |
5  |         Value::Number { key, .. } | Value::Text { key, .. } => {
   |                                                   --- value moved here
...
10 |             match v {
   |                   ^ value used here after partial move
   |
   = note: move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `v.key`
   |
5  |         Value::Number { key, .. } | Value::Text { ref key, .. } => {
   |                                                   ^^^

If I do what the hint says, I would have to make a copy of key before I can feed it to consume_string().

What are my options?

1 Like

One way you could go about this is to use std::mem::take like so. Playground
mem::take will replace key with the default value of String, and return the previous value. This is inexpensive as String::default just returns an empty string, so there is no extra allocation here.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.