简体   繁体   English

在HashMap中存储闭包

[英]Storing a closure in a HashMap

To learn the Rust language, I'm taking an old C++ library I had lying around and trying to convert it to Rust. 为了学习Rust语言,我正在使用一个旧的C ++库,我已经躺在那里并尝试将其转换为Rust。 It used a lot of C++11 closures and I'm having some difficulty getting the concepts to translate. 它使用了很多C ++ 11闭包,我在翻译概念方面遇到了一些困难。

In C++ I had something like this: 在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;
}

The part that I'm having trouble with is properly storing the functions in a Rust HashMap collection. 我遇到问题的部分是将函数正确存储在Rust HashMap集合中。 I tried this: 我试过这个:

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); 
    }
}

but it says the trait core::marker::Sized is not implemented for the type 'for('r) core::ops::FnMut(&'r CreateEvent)' 但它表示the trait core::marker::Sized is not implemented for the type 'for('r) core::ops::FnMut(&'r CreateEvent)'

This makes sense because FnMut is a trait, and therefore has no known size for the HashMap to make at compile time. 这是有道理的,因为FnMut是一个特征,因此在编译时没有已知的HashMap大小。 So I figure that the hashmap would require an actual pointer rather than an abstract type. 所以我认为hashmap需要一个实际的指针而不是一个抽象类型。 So I change it to this 所以我把它改成了这个

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));
    }
}

now it says the trait 'for('r) core::ops::Fn<(&'r CreateEvent,)>' is not implemented for the type '&for('r) core::ops::FnMut(&'r CreateEvent)' [E0277] at the insert. 现在它说the trait 'for('r) core::ops::Fn<(&'r CreateEvent,)>' is not implemented for the type '&for('r) core::ops::FnMut(&'r CreateEvent)' [E0277]在插入处。 This error makes no sense to me at all. 这个错误对我来说毫无意义。 Can someone explain to me the proper way to store a reference to a non-escaping closure in a HashMap? 有人可以向我解释在HashMap中存储对非转义闭包的引用的正确方法吗?

You have taken a &FnMut(&Event) —a trait object—and, after boxing it, wish to store it as a Box<FnMut(&Event)> . 你已经采取了&FnMut(&Event) -a trait对象 - 并且在装箱之后,希望将其存储为Box<FnMut(&Event)> Thus, you require that &FnMut(&Event) must implement FnMut(&Event) , which it does not (and clearly cannot, for FnMut.call_mut takes &mut self ). 因此,你需要&FnMut(&Event)必须实现FnMut(&Event) ,它不会(并明确不能, FnMut.call_mut需要&mut self )。

What you wanted was to take an arbitrary type that implements FnMut(&Event) —that is, use generics—and take it by value. 你想要的是采用一个实现 FnMut(&Event)的任意类型 - 也就是说,使用泛型 - 并按值获取它。 The signature is thus this: 签名就是这样的:

fn make_func<F: FnMut(&Event)>(&mut self, s: &str, f: F)

It gets a little more complex than this due to lifetimes, however, but what you wish to do with regards to that may vary; 然而,由于生命周期,它比这更复杂,但你想做的事情可能会有所不同; Storing an unboxed closure with a reference arg in a HashMap has more information on that topic. 在HashMap中存储带有引用arg的未装箱闭包有关于该主题的更多信息。 Here's what I believe you're most likely to want: 这是我认为你最想要的东西:

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));
    }
}

You could remove all the 'a in favour of just a single + 'static bound on F if you are happy to not let any of the closures capture references to their environments. 如果您乐意不让任何闭包捕获对其环境的引用,则可以删除F上的所有'a赞成单个+ 'static绑定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM