在HashMap中存储闭包

时间:2015-03-23 01:49:27

标签: rust

为了学习Rust语言,我选择了一个旧的C ++库,并将其转换为Rust。它使用了大量的C ++ 11闭包,我在翻译概念方面遇到了一些困难。

在C ++中,我有类似的东西:

// library.h
struct Event {
    // just some data
};

class Object {
public:
    // ...
    std::function<void(Event&)>& makeFunc(std::string& s) {
        return m_funcs[s];
    }
    // ...
private:
    // ...
    std::map<std::string, std::function<void(Event&)>> m_funcs;
    // ...
};

// main.cpp using the library
int main()
{
    Object foo;
    foo.makeFunc("func1") = [&]{
        // do stuff
    };
    return 0;
}

我遇到问题的部分是将函数正确存储在Rust HashMap集合中。我试过这个:

struct Event;

struct Object {
    m_funcs : HashMap<String, FnMut(&Event)>
}

impl Object {
    // send f as another parameter rather than try and return borrow
    // compiler was complaining
    fn makeFunc(&mut self, s : &str,f: FnMut(&Event)) {
        self.m_funcs.insert(String::from_str(s), f); 
    }
}

但它说the trait core::marker::Sized is not implemented for the type 'for('r) core::ops::FnMut(&'r CreateEvent)'

这是有道理的,因为FnMut是一个特征,因此在编译时没有已知的HashMap大小。所以我认为hashmap需要一个实际的指针而不是一个抽象类型。所以我把它改成了

struct Object {
    m_funcs : HashMap<String, Box<FnMut(&Event)>>
}

impl Object {
    fn makeFunc(&mut self, s : &str, f: &FnMut(&Event)) {
        self.m_funcs.insert(String::from_str(s), Box::new(f));
    }
}

现在它在插入处显示the trait 'for('r) core::ops::Fn<(&'r CreateEvent,)>' is not implemented for the type '&for('r) core::ops::FnMut(&'r CreateEvent)' [E0277]。这个错误对我来说毫无意义。有人可以向我解释在HashMap中存储对非转义闭包的引用的正确方法吗?

1 个答案:

答案 0 :(得分:6)

你已经拍摄了&FnMut(&Event) - 一个特质对象 - 并且在装箱之后,希望将其存储为Box<FnMut(&Event)>。因此,您要求&FnMut(&Event)必须实现FnMut(&Event),而FnMut.call_mut必须&mut self才能实现FnMut(&Event)

你想要的是采用实现 fn make_func<F: FnMut(&Event)>(&mut self, s: &str, f: F) 的任意类型 - 也就是说,使用泛型 - 并按值获取它。签名是这样的:

struct Object<'a> {
    m_funcs: HashMap<String, Box<FnMut(&Event) + 'a>>,
}

impl<'a> Object<'a> {
    fn make_func<F: FnMut(&Event) + 'a>(&mut self, s: &str, f: F) {
        self.m_funcs.insert(String::from_str(s), Box::new(f));
    }
}

然而,由于生命周期,它比这更复杂,但你想做的事情可能会有所不同; Storing an unboxed closure with a reference arg in a HashMap有关于该主题的更多信息。以下是我认为你最想要的东西:

'a

如果您愿意不让任何关闭功能捕获对其环境的引用,则可以删除所有+ 'static,而只支持F上的{{1}}绑定。