rustborrow-checkermutability

How to call FnMut stored in the collection? (error: cannot borrow `*handler` as mutable, as it is behind a `&` reference)


I'm a newbuy in Rust. I need to store a collection of closures (fn_list) that can use variables from the context, after that I need to call these closures.

Playground code:

pub struct MyScope {
    pub fn_list: HashMap<String, Box<dyn FnMut(String)>>,
}

fn main() {
    let hello = "Hello";
    
    let closure = move |name: String|{
        println!("{} {}!", hello, name);
    };
    
    let mut list = HashMap::new();
    list.insert(
        "world".to_string(),
        Box::new(closure) as Box<dyn FnMut(String)>
    );
    
    let scope = MyScope {
        fn_list: list
    };
    
    for (name, handler) in &scope.fn_list {
        handler(name.clone());
    }
}

But I've got the error:

cannot borrow *handler as mutable, as it is behind a & reference
handler is a & reference, so the data it refers to cannot be borrowed as mutable

How to fix it?


Solution

  • The error message is very clear. Here's the full text:

    cannot borrow `*handler` as mutable, as it is behind a `&` reference
      --> src/main.rs:25:9
       |
    24 |     for (name, handler) in &scope.fn_list {
       |                            -------------- this iterator yields `&` references
    25 |         handler(name.clone());
       |         ^^^^^^^ `handler` is a `&` reference, so the data it refers to cannot be borrowed as mutable
    

    Fixing that, by borrowing the functions mutably:

        for (name, handler) in &mut scope.fn_list {
            handler(name.clone());
        }
    

    yields another error, but also a helpful suggestion on how to fix it:

    cannot borrow `scope.fn_list` as mutable, as `scope` is not declared as mutable
      --> src/main.rs:24:28
       |
    24 |     for (name, handler) in &mut scope.fn_list {
       |                            ^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
       |
    help: consider changing this to be mutable
       |
    20 |     let mut scope = MyScope {
       |         +++