【问题标题】:Storing a closure in a HashMap在 HashMap 中存储闭包
【发布时间】:2015-03-23 21:33:05
【问题描述】:

为了学习 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(&amp;'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&lt;(&amp;'r CreateEvent,)&gt;' is not implemented for the type '&amp;for('r) core::ops::FnMut(&amp;'r CreateEvent)' [E0277]。这个错误对我来说毫无意义。有人可以向我解释在 HashMap 中存储对非转义闭包的引用的正确方法吗?

【问题讨论】:

    标签: rust


    【解决方案1】:

    你已经获取了一个&amp;FnMut(&amp;Event)——一个特征对象——并且在装箱之后,希望将它存储为Box&lt;FnMut(&amp;Event)&gt;。因此,您要求&amp;FnMut(&amp;Event) 必须实现FnMut(&amp;Event),但它没有实现(显然不能,因为FnMut.call_mut 需要&amp;mut self)。

    您想要的是采用 实现 FnMut(&amp;Event) 的任意类型(即使用泛型)并按值获取。因此签名是这样的:

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

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

    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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多