Rust compilation error: 'move occurs because `self.styles` has type `HashMap<&str, &str>`'

Viewed 349

I have been trying to write simple logger "class" that can display test message in colors. I am running into the compilation error. What am i doing wrong and how can i fix it ? (please note i'd like to fix this particular issue not to replace what i am doing with some coloring crate, etc... it's a learning exercise for me).

error[E0507]: cannot move out of `self.styles` which is behind a shared reference
  --> src/main.rs:21:30
   |
21 |         for (style, term) in self.styles {
   |                              ^^^^^^^^^^^ move occurs because `self.styles` has type `HashMap<&str, &str>`, which does not implement the `Copy` trait

Code...

use std::collections::HashMap;

struct Logger <'a> {
    styles: HashMap<&'a str, &'a str>,
}

impl Logger <'_> {
    fn new() -> Logger <'static> {
        let mut logger = Logger{styles: HashMap::new()};
        logger.styles.insert("</>", "\x1b[0m");
        logger.styles.insert("<WARN>", "\x1b[1m\x1b[93m");
        logger.styles.insert("<CRIT>", "\x1b[41m");
        logger.styles.insert("<INFO>", "\x1b[1m");
        logger
    }

    fn log(&self, message: &str) {
        let mut output = String::new();
        for (style, term) in self.styles {
            output = message.replace(style, term);
        }
        println!("{}", output)
    }
}

fn main() {
    let logger = Logger::new();

    logger.log("<INFO>Logger</> written in <CRIT>Rust</> language, <WARN>2021</>");
}
1 Answers

The for loop has an implicit call to .into_iter(). From the docs (emphasis mine):

Creates a consuming iterator, that is, one that moves each key-value pair out of the map in arbitrary order. The map cannot be used after calling this.

So the for loop is trying to move self.styles since it doesn't implement the Copy trait. Try borrowing instead:

for (&style, &term) in &self.styles {
    ...
}
Related