How can I prevent using clone() here?

I was advised to avoid clone() whenever possible. How can I avoid using clone() in the following code?

#[derive(Debug, Default, Clone)]
pub struct Keymap {
    pub key: char,
    pub command: String,
    pub description: String,
    pub prompt: Option<String>,
}

impl Keymap {
    pub fn new<S: AsRef<str>>(key: char, command: S) -> Self {
        let command = command.as_ref().to_owned();
        let description = command.clone();

        Self {
            key,
            command,
            description,
            ..Default::default()
        }
    }
}

fn handle_keymap_prompt(prompt: Option<String>) {
    println!("Do something with prompt: {:?}", prompt);
}

fn handle_keymap(keymap: &Keymap) {
    println!("Do something with keymap{:?}", keymap);
}

fn main() {
    let keymaps = vec![Keymap::new('t', "echo 'test'")];

    if let Some(keymap) = keymaps.iter().find(|k| k.key == 't') {
        handle_keymap_prompt(keymap.prompt.clone());
        handle_keymap(keymap);
    }
}

Rust Playground

Note: this is the simplified version of the original code.

If I remove clone() from keymap.prompt, I get this error:

error[E0507]: cannot move out of `keymap.prompt` which is behind a shared reference
  --> src/main.rs:35:30
   |
35 |         handle_keymap_prompt(keymap.prompt);
   |                              ^^^^^^^^^^^^^ move occurs because `keymap.prompt` has type `Option<String>`, which does not implement the `Copy` trait

Then just take a reference to it.

That would, however, lead to the handle_keymap_prompt() function taking an &Option<String>. Generally, requiring explicitly borrowing owned data is an anti-pattern, because then the caller must allocate that specific kind of owning data (here, String).

Thus, you should accept an Option<&str> instead, which leads to the use of .as_deref(). Playground.

4 Likes