【问题标题】:Call closure, that's in a collection, with the owner of the collection调用闭包,即在集合中,与集合的所有者
【发布时间】:2015-08-19 23:56:23
【问题描述】:

考虑以下代码:

use std::collections::HashMap;
type KeyCode = char;
type CmdType = Fn(&mut E);

struct E {
    key_map: HashMap<KeyCode, Box<CmdType>>,
}

impl E {
    fn map_key(&mut self, key: KeyCode, function: Box<CmdType>) {
        self.key_map.insert(key, function);
    }
    fn quit(&mut self) { println!("quitting"); /* ... */ }
}

fn main() {
    let mut e = E { key_map: HashMap::new() };
    e.map_key('q', Box::new(|e: &mut E| e.quit()));

    match e.key_map.get(&'q') {
        Some(f) => f(&mut e),
        None => {}
    }
}

其中doesn't compile 因为我试图将e 传递给f

不能将e 借用为可变的,因为e.key_map 也借用为不可变的

但是当e.key_map 的借用结束时,我将无法再访问f。那么我该如何准确地调用地图内的闭包呢?

【问题讨论】:

    标签: compiler-errors rust borrow-checker


    【解决方案1】:

    那么我该如何准确地调用地图内部的闭包呢?

    这取决于合适的行为。

    如你所见,如果f 是从e 借用的,那么调用f(&amp;mut e) 是不可能的。解决方案是

    • 不要将&amp;mut e 传递给函数。如果E 不在您的控制之下,这是不切实际的。

    • 停止fe 借用。由于CmdType 不是Cloneable,因此不能简单地将其复制出来。但是,您应该可以暂时从地图中删除 f

      let removed = e.key_map.remove(&'q');
      if let Some(f) = removed {
          f(&mut e);
          e.key_map.insert('q', f);
      }
      

    【讨论】:

    • 闭包必须以某种方式访问​​e。现在我只是将key_map 存储在E 之外,并在E 中保留了对它的引用。这也是不切实际的,但至少它有效。
    【解决方案2】:

    一种解决方案是让E拥有地图,如果合适的话,而是将该功能分离到另一个结构中。像这样的:

    struct K {
        key_map: HashMap<KeyCode, Box<CmdType>>,
    }
    
    impl K {
        fn map_key(&mut self, key: KeyCode, function: Box<CmdType>) {
            self.key_map.insert(key, function);
        }
    }
    
    struct E;
    
    impl E {
        fn quit(&mut self) { println!("quitting"); /* ... */ }
    }
    
    fn main() {
        let mut k = K { key_map: HashMap::new() };
        k.map_key('q', Box::new(|e: &mut E| e.quit()));
    
        let mut e = E;
        match k.key_map.get(&'q') {
            Some(f) => f(&mut e),
            None => {}
        }
    }
    

    E 也可能在需要时引用K 实例。

    【讨论】:

      猜你喜欢
      • 2021-05-08
      • 1970-01-01
      • 2011-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 2017-05-31
      • 1970-01-01
      相关资源
      最近更新 更多