以下代码 ( playground ) 无法编译:
async fn wrapper<F, Fut>(func: F)
where
F: FnOnce(&i32) -> Fut,
Fut: Future<Output = ()>,
{
let i = 5;
func(&i).await;
}
async fn myfunc(_: &i32) {}
fn main() {
wrapper(myfunc);
}
Run Code Online (Sandbox Code Playgroud)
错误信息是:
error: implementation of `std::ops::FnOnce` is not general enough
--> src/main.rs:15:5
|
15 | wrapper(myfunc);
| ^^^^^^^ implementation of `std::ops::FnOnce` is not general enough
|
= note: `std::ops::FnOnce<(&'0 i32,)>` would have to be implemented for the type `for<'_> fn(&i32) -> impl std::future::Future {myfunc}`, for some specific lifetime `'0`...
= note: ...but `std::ops::FnOnce<(&i32,)>` is actually implemented for the type `for<'_> fn(&i32) -> impl std::future::Future {myfunc}`
Run Code Online (Sandbox Code Playgroud)
我发现了一些提到 HRTB 的类似项目(例如这个 Rust 问题和这个),并尝试尝试使用for<'a>额外的生命周期界限,但我仍然不清楚错误。
我不明白为什么编译器不能确定生命周期,特别是因为没有期货的简单版本编译得很好:
fn myfunc(_: &i32) {}
fn wrapper<F: FnOnce(&i32)>(func: F) {
let i = 5;
func(&i);
}
fn main() {
wrapper(myfunc);
}
Run Code Online (Sandbox Code Playgroud)
所以,我想问一下:
从您提供的问题中解释的内容开始,可以为您的包装器期望的功能创建特定的特征。
作为我自己对 Rust 相当陌生,我不知道为什么在你的原始版本中,编译器会抱怨显示的错误消息中实际上等效的不匹配类型(当我们有显式生命周期时,这一点更加明显;显示的类型完全匹配) !)。我只是猜测这是因为确切的结果类型隐藏在符号后面impl,而实际的差异在于这个隐藏的部分。
确实很难表达参数和结果都应该考虑任何生命周期,因为它们出现在子句的两个不同约束上。据我了解(不是那么多......),考虑整个特征的显式生命周期使得参数和结果的表示法一致,因为所有这些都处于子句的相同约束中。for<'r>&Futurewherefor<'r>&Futurewhere
由于我们正在处理生命周期,因此我决定将可复制的替换i32为不可复制的String,以防止发生任何意外的简化。
正如您提供的链接中所述,该解决方案似乎仅适用于函数,不适用于闭包。
use std::future::Future;
async fn wrapper<F>(func: F)
where
F: for<'r> Wrapped<'r>,
{
let s = String::from("WRAPPED");
func.call_once(&s).await;
}
trait Wrapped<'a> {
type Res: Future<Output = ()>;
fn call_once(
self,
s: &'a String,
) -> Self::Res;
}
impl<'a, F, FutRes> Wrapped<'a> for F
where
F: FnOnce(&'a String) -> FutRes,
FutRes: Future<Output = ()> + 'a,
{
type Res = FutRes;
fn call_once(
self,
s: &'a String,
) -> Self::Res {
self(s)
}
}
async fn call_myfunc() {
let s = String::from("HARDCODED");
myfunc(&s).await;
}
async fn myfunc(arg: &String) {
println!("arg={}", arg);
}
fn main() {
println!("~~~~ hardcoded call ~~~~");
let f = call_myfunc();
futures::executor::block_on(f);
println!("~~~~ use wrapper() ~~~~");
let f = wrapper(myfunc);
futures::executor::block_on(f);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1226 次 |
| 最近记录: |