gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 11:48:04 25 4
gpt4 key购买 nike

我正在使用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/

25 4 0