Dem*_*gos 5 closures asynchronous lifetime rust
我试图传递一个返回Future<Output=bool>到异步函数的闭包,并将此闭包称为异步谓词(类似于异步.filter或其他高阶函数)。
该谓词接收其输入作为引用。我找到了如何为不捕获其环境的纯谓词实现它:
type BoxFuture<'a, Out> = Pin<Box<dyn Future<Output=Out> + 'a + Send>>;
////////////////////////////////////////////////////////////////////////////////
// 1 -> Closure only uses the inner argument //
////////////////////////////////////////////////////////////////////////////////
/// Run the computation and check that its output is not empty
fn run1<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
async move {
let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
b.len() > 0 // Only uses the inner argument
}));
let is_ok1 = is_ok.await;
dbg!(is_ok1);
}
}
/// Compute some bytes (may be complex / use async), then check their validity
/// with a user-supplied function, finally do some clean-up and return.
async fn compute_and_check1<F>(check: F) -> bool
where
F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'r, bool>
{
let bytes = [0u8; 128];
let is_ok = check(&bytes).await;
drop(bytes);
is_ok
}
Run Code Online (Sandbox Code Playgroud)
仅支持非捕获闭包是相当有限的。我想使用一个捕获其环境的闭包。通过更改函数的边界compute_and_check,我能够传递使用其环境的闭包 - 但不能传递其输入:
type BoxFuture<'a, Out> = Pin<Box<dyn Future<Output=Out> + 'a + Send>>;
////////////////////////////////////////////////////////////////////////////////
// 2 -> Closure only uses the outer argument //
////////////////////////////////////////////////////////////////////////////////
/// Run the computation and assume that its output is not empty if `expected` is not empty
fn run2<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
async move {
let is_ok = compute_and_check2(|b: &[u8]| Box::pin(async move {
expected.len() > 0 // Only uses the environment
}));
let is_ok2 = is_ok.await;
dbg!(is_ok2);
}
}
/// Compute some bytes (may be complex / use async), then check their validity
/// with a user-supplied function, finally do some clean-up and return.
async fn compute_and_check2<'a, F>(check: F) -> bool
where
F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'a, bool>
{
let bytes = [0u8; 128];
let is_ok = check(&bytes).await;
drop(bytes);
is_ok
}
Run Code Online (Sandbox Code Playgroud)
我可以编写一种实现,其中闭包使用其输入,以及闭包使用其环境。但不能同时两者。
我如何接受一个使用其输入和环境引用的未来生产闭包?
我想写的是这样的:
type BoxFuture<'a, Out> = Pin<Box<dyn Future<Output=Out> + 'a + Send>>;
////////////////////////////////////////////////////////////////////////////////
// 3 -> Closure uses both the inner and outer arguments //
////////////////////////////////////////////////////////////////////////////////
/// Run the computation and check its output is the provided expected value
fn run3<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
async move {
let is_ok = compute_and_check3(|b: &[u8]| Box::pin(async move {
b == expected // Uses both the input and environment
}));
let is_ok2 = is_ok.await;
dbg!(is_ok2);
}
}
/// Compute some bytes (may be complex / use async), then check their validity
/// with a user-supplied function, finally do some clean-up and return.
async fn compute_and_check3<'a, F>(check: F) -> bool
where
F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'r + 'a, bool>
{
let bytes = [0u8; 128];
let is_ok = check(&bytes).await;
drop(bytes);
is_ok
}
Run Code Online (Sandbox Code Playgroud)
此代码无法编译,因为我要求闭包返回BoxFuture<'r + 'a, bool>,但这不是合法的语法:
error[E0226]: only a single explicit lifetime bound is permitted
--> src/main.rs:89:51
|
89 | F: for<'r> FnOnce(&'r [u8]) -> BoxFuture<'r + 'a, bool>
| ^^
Run Code Online (Sandbox Code Playgroud)
据我了解,我的问题的核心是我需要限制我的高级特质束缚。'r我想说的不是“对于任何”,而是“对于任何'r不会过时的'a”,但我不知道如何写下来。
我尝试对我的BoxFuture类型别名使用两个生命周期和限制,或者定义一个辅助特征,但我没有设法解决这个问题,因为我未能对 HRTB 生命周期应用限制。
compute_and_check1为了完整起见,以下是将最终闭包传递给(仅输入)和compute_and_check2(仅环境)时出现的错误:
使用compute_and_check1(仅输入)playground 链接
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:17:67
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| ___________________________________________________________________^
18 | | b == expected
19 | | }));
| |_____^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 15:9...
--> src/main.rs:15:9
|
15 | fn run3<'a>(expected: &'a [u8]) -> impl Future<Output=()> + 'a {
| ^^
note: ...so that the types are compatible
--> src/main.rs:17:67
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| ___________________________________________________________________^
18 | | b == expected
19 | | }));
| |_____^
= note: expected `(&[u8], &[u8])`
found `(&[u8], &'a [u8])`
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 17:36...
--> src/main.rs:17:36
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| ____________________________________^
18 | | b == expected
19 | | }));
| |______^
note: ...so that the expression is assignable
--> src/main.rs:17:47
|
17 | let is_ok = compute_and_check1(|b: &[u8]| Box::pin(async move {
| _______________________________________________^
18 | | b == expected
19 | | }));
| |______^
= note: expected `Pin<Box<dyn Future<Output = bool> + Send>>`
found `Pin<Box<dyn Future<Output = bool> + Send>>`
Run Code Online (Sandbox Code Playgroud)
使用compute_and_check2(仅环境)playground 链接
error: lifetime may not live long enough
--> src/main.rs:17:47
|
17 | let is_ok = compute_and_check2(|b: &[u8]| Box::pin(async move {
| ________________________________________-____-_^
| | | |
| | | return type of closure is Pin<Box<(dyn Future<Output = bool> + Send + '2)>>
| | let's call the lifetime of this reference `'1`
18 | | b == expected
19 | | }));
| |______^ returning this value requires that `'1` must outlive `'2`
Run Code Online (Sandbox Code Playgroud)
我还研究了夜间功能,unboxed_closure但未能解决我的问题。我希望我的代码能够在稳定的 Rust 上运行,但如果这是唯一的解决方案,我的代码要求 nightly 也是可以接受的。
| 归档时间: |
|
| 查看次数: |
725 次 |
| 最近记录: |