在 HashMap 中存储闭包
Storing a closure in a HashMap
为了学习 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 中存储对非转义闭包的引用的正确方法吗?
您获取了一个 &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));
}
}
如果您愿意不让任何闭包捕获对其环境的引用,则可以删除所有 'a
以支持 F
上的单个 + 'static
绑定。
为了学习 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 中存储对非转义闭包的引用的正确方法吗?
您获取了一个 &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));
}
}
如果您愿意不让任何闭包捕获对其环境的引用,则可以删除所有 'a
以支持 F
上的单个 + 'static
绑定。