[英]“expected bound lifetime parameter, found concrete lifetime” on StreamExt .scan() method
I am using async-tungstenite to listen to a websocket, and async-std's StreamExt to operate on the resulting stream.我正在使用 async-tungstenite 监听 websocket,并使用 async-std 的 StreamExt 对生成的 stream 进行操作。
I want to use a HashMap to accumulate the latest Ticker values from the websocket.我想使用 HashMap 从 websocket 中累积最新的 Ticker 值。 These Ticker values will be looked up later to be used in calculations.
稍后将查找这些 Ticker 值以用于计算。 I'm using the symbol (String) value of the Ticker struct as the key for the HashMap.
我使用 Ticker 结构的符号(字符串)值作为 HashMap 的键。 I'm using the.scan StreamExt method to perform the accumulation.
我正在使用 .scan StreamExt 方法来执行累积。
However, I get a compilation error related to lifetimes.但是,我收到与生命周期相关的编译错误。 Here's some stripped-down code:
这是一些精简的代码:
let tickers = HashMap::new();
let mut stream = ws.
.scan(tickers, accumulate_tickers);
while let msg = stream.next().await {
println!("{:?}", msg)
}
...and the accumulate_tickers function: ...以及累积的代码 function:
fn accumulate_tickers(tps: &mut HashMap<String, Ticker>, bt: Ticker) -> Option<&HashMap<String, Ticker>> {
tps.insert((*bt.symbol).to_string(), bt);
Some(tps)
}
The compilation error I receive is as follows:我收到的编译错误如下:
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
I'm unaware of a way to provide a lifetime parameter to the scan method.我不知道有一种方法可以为扫描方法提供生命周期参数。
I wonder whether the issue may be related to the fact that I modify the HashMap and then try to return it (is it a move issue?).我想知道这个问题是否可能与我修改了 HashMap 然后尝试退货有关(是移动问题吗?)。 How could I resolve this, or at least narrow down the cause?
我该如何解决这个问题,或者至少缩小原因?
I was able to get this working.我能够得到这个工作。 Working my way through the compiler errors, I ended up with this signature for the
accumulate_tickers
function:通过编译器错误,我最终得到了
accumulate_tickers
function 的签名:
fn accumulate_tickers<'a>(tps: &'a mut &'static HashMap<String, Ticker>, bt: Ticker) -> Option<&'static HashMap<String, Ticker>>
I do want the accumulator HashMap to have a static lifetime so that makes sense.我确实希望累加器 HashMap 具有 static 寿命,所以这是有道理的。
tps: &'a mut &'static HashMap...
does look a bit strange, but it works. tps: &'a mut &'static HashMap...
确实看起来有点奇怪,但它确实有效。
Then, this issue was was that tickers
also had to have a static lifetime (it's the initial value for the accumulator. I tried declaring it as static outside the main
but it wouldn't let me set it to the result of a function - HashMap::new()
. Then, this issue was was that
tickers
also had to have a static lifetime (it's the initial value for the accumulator. I tried declaring it as static outside the main
but it wouldn't let me set it to the result of a function - HashMap::new()
。
I then turned to lazy_static which allows me to create a static value which does just that:然后我转向lazy_static ,它允许我创建一个static值,它就是这样做的:
lazy_static! {
static ref tickers: HashMap<String, Ticker> = HashMap::new();
}
This gave me a HashMap accumulator that had a static lifetime.这给了我一个具有 static 寿命的 HashMap 累加器。 However, like normal static values declared in the root scope, it was immutable.
然而,就像在根 scope 中声明的正常 static 值一样,它是不可变的。 To fix that, I read some hints from the lazy_static team and then found https://pastebin.com/YES8dsHH .
为了解决这个问题,我阅读了lazy_static 团队的一些提示,然后找到了 https://pastebin.com/YES8dsHH 。 This showed me how to make my static accumulator mutable by wrapping it in
Arc<Mutex<_>>
.这向我展示了如何通过将 static 累加器包装在
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))
};
}
This does mean that I have to retrieve the accumulator from the Mutex (and lock it) before reading or modifying it but, again, it works.这确实意味着我必须在读取或修改它之前从 Mutex 中检索累加器(并锁定它),但它再次起作用。
Putting it all together, the stripped-down code now looks like this:把它们放在一起,精简后的代码现在看起来像这样:
#[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)
}
I'd be happy to hear suggestions for ways in which this could be made simpler or more elegant.我很高兴听到有关如何使这变得更简单或更优雅的建议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.