rust - StreamExt .scan()方法上的“expected bound lifetime parameter, found concrete lifetime”

标签 rust hashmap lifetime

我正在使用async-tungstenite来监听websocket,并使用async-std的StreamExt对结果流进行操作。
我想使用HashMap从websocket累积最新的股票行情指示器值。这些股票行情值将在以后查找以用于计算。我正在使用Ticker结构的symbol(String)值作为HashMap的键。我正在使用.scan StreamExt方法执行累积。
但是,我收到与生存期有关的编译错误。这是一些简化的代码:

        let tickers = HashMap::new();
        let mut stream = ws.
            .scan(tickers, accumulate_tickers);
        while let msg = stream.next().await {
            println!("{:?}", msg)
        }
...以及accumulate_tickers函数:
fn accumulate_tickers(tps: &mut HashMap<String, Ticker>, bt: Ticker) -> Option<&HashMap<String, Ticker>> {
    tps.insert((*bt.symbol).to_string(), bt);
    Some(tps)
}
我收到的编译错误如下:
error[E0271]: type mismatch resolving `for<'r> <for<'s> fn(&'s mut std::collections::HashMap<std::string::String, ws_async::model::websocket::Ticker>, ws_async::model::websocket::Ticker) -> std::option::Option<&'s std::collections::HashMap<std::string::String, ws_async::model::websocket::Ticker>> {accumulate_tickers} as std::ops::FnOnce<(&'r mut std::collections::HashMap<std::string::String, ws_async::model::websocket::Ticker>, ws_async::model::websocket::Ticker)>>::Output == std::option::Option<_>`
--> examples/async_std-ws.rs:64:4
   |
64 |         .scan(tickers, accumulate_tickers);
   |          ^^^^ expected bound lifetime parameter, found concrete lifetime
我不知道一种为扫描方法提供生命周期参数的方法。
我想知道问题是否与我修改HashMap然后尝试返回它的事实有关(这是一个移动问题吗?)。我该如何解决,或者至少缩小原因?

最佳答案

我能够做到这一点。在解决编译器错误的过程中,我最终获得了accumulate_tickers函数的以下签名:

fn accumulate_tickers<'a>(tps: &'a mut &'static HashMap<String, Ticker>, bt: Ticker) -> Option<&'static HashMap<String, Ticker>>
我确实希望累加器HashMap具有静态生存期,这样才有意义。 tps: &'a mut &'static HashMap...看起来确实有些奇怪,但是可以工作。
然后,问题是tickers还必须具有静态生存期(这是累加器的初始值。我尝试在main之外将其声明为静态,但不允许我将其设置为函数的结果-HashMap::new()
然后,我转向lazy_static,它允许我创建一个静态值,该静态值可以做到这一点:
lazy_static! {
    static ref tickers: HashMap<String, Ticker> = HashMap::new();
}
这给了我一个具有静态生存期的HashMap累加器。但是,就像在根作用域中声明的普通静态值一样,它是不可变的。为了解决这个问题,我阅读了lazy_static团队的一些提示,然后找到了https://pastebin.com/YES8dsHH。这向我展示了如何通过将其包装在Arc<Mutex<_>>中来使我的静态累加器可变。
lazy_static! {
    // from https://pastebin.com/YES8dsHH
    static ref tickers: Arc<Mutex<HashMap<String, Ticker>>> = {
        let mut ts = HashMap::new();
        Arc::new(Mutex::new(ts))
    };
}
这确实意味着我必须在读取或修改它之前从Mutex中检索累加器(并锁定它),但是再次起作用。
将所有内容放在一起,现在精简的代码如下所示:
#[macro_use]
extern crate lazy_static;

lazy_static! {
    // from https://pastebin.com/YES8dsHH
    static ref tickers: Arc<Mutex<HashMap<String, Ticker>>> = {
        let mut ts = HashMap::new();
        Arc::new(Mutex::new(ts))
    };
}

// SNIP

    // Inside main()
    let mut ticks = ws
        .scan(&tickers, accumulate_tickers);
    while let Some(msg) = ticks.next().await {
        println!("{:?}", msg.lock().unwrap());
    }

// SNIP

fn accumulate_tickers<'a>(tps: &'a mut &'static tickers, bt: Ticker) -> Option<&'static tickers> {
    tps.lock().unwrap().insert((*bt.symbol).to_string(), bt);
    Some(tps)
}
我很高兴听到关于可以使之更简单或更优雅的建议。

关于rust - StreamExt .scan()方法上的“expected bound lifetime parameter, found concrete lifetime”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63193627/

相关文章:

rust - 如何在 Rust future 中赋予所有权

rust - 如何在关联类型中指定生命周期参数?

rust - 允许针对不同版本的源代码进行互操作的确切机制是什么?

winapi - FileCreate 的一些问题

rust - 为什么在名为!的宏中将 nom 的 CompleteStr 转换为字符串?返回结果?

rust - 如果大小写不匹配,如何反序列化枚举?

java - 通用对象的哈希函数

java - 查找对象中某些属性值作为 HashMap 值的出现次数的有效方法

java - 获取最后一个 Hashmap 键的值

WCF 服务以及围绕客户端和打开/关闭方法的最佳实践