< 返回版块

dvorakchen 发表于 2023-06-06 15:52

Tags:rust

use core::future::Future;

async fn handle(req: &str) -> u32 {
 println!("{:?}", req);
 123123
}

async fn make_service<F, Fut>(f: F)
where
F: for<'a> Fn(&'a str) -> Fut + Clone + 'static,
 Fut: Future<Output = u32>,
{
 println!("result = {}", f("req").await);
}

#[tokio::main]
async fn main() {
 make_service(handle);
}

报错信息如下:

error[E0308]: mismatched types
  --> src/main.rs:18:2
   |
18 |  make_service(handle);
   |  ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected opaque type `impl for<'a> Future<Output = u32>`
              found opaque type `impl Future<Output = u32>`
   = help: consider `await`ing on both `Future`s
   = note: distinct uses of `impl Trait` result in different opaque types
note: the lifetime requirement is introduced here
  --> src/main.rs:10:16
   |
10 | F: Fn(&str) -> Fut + Clone + 'static,
   |                ^^^

For more information about this error, try `rustc --explain E0308`.

没有明白,求教各位大佬,有什么知识点

评论区

写评论
zhylmzr 2023-06-08 10:59

另外解释一下报错信息具体是什么意思:

note: expected opaque type impl for<'a> Future<Output = u32> found opaque type impl Future<Output = u32>

第二行提示的是实际传入的类型是impl Future<Output = u32> 也就是 Fut,它没有任何的捕获生命周期,但是期望的类型却需要捕获生命周期。

zhylmzr 2023-06-08 10:52
use core::future::Future;

async fn handle(req: &str) -> u32 { 
    println!("{:?}", req);          //                      (1)
    123123
}

async fn make_service<F, Fut>(f: F)
where
    F: for<'a> Fn(&'a str) -> Fut + Clone + 'static, //     (2)
    Fut: Future<Output = u32>,                       //     (3)
{
    println!("result = {}", f("req").await);
}

#[tokio::main]
async fn main() {
    make_service(handle);
}

handle 函数因为(1)的缘故,返回的impl Future会捕获req, 那么它的impl Future生命周期和req一致. 根据(2)的约束,F作为一个函数,它的返回值Fut和参数&'a str的生命周期'a没有关系(注意这里的'static只是标注了F的生命周期) 所以问题的根本在于FFut的生命周期不一致导致的问题。 修改make_service签名以让FFut使用同一个生命周期即可:

async fn make_service<'a, F, Fut>(f: F)
where
    F: Fn(&'a str) -> Fut + Clone + 'static,
    Fut: Future<Output = u32> + 'a,
{
    println!("result = {}", f("req").await);
}

在线尝试

github.com/shanliu/lsys 2023-06-07 00:58

按提问的意思应该是想吧_a放到异步里去 所以【苦瓜小仔】的装箱future估计才是他要的结果

--
👇
zylthinking: 首先, async fn handle(req: &str) -> u32 这种写法, 不会满足原型: for<'a> Fn(&'a str) -> Fut + Clone + 'static, 它只会认为返回的 future 捕获了 req; 若想表达其实没有捕获 req, 使用明确的语法, 别用语法糖。

其次, 你是真的捕获了 req, 你在 future 里面打印了 req

所以, 最大的问题并不是你的语法问题, 而是你切切实实写出了 bug; 自然, 看上去你语法其实也没搞明白, 但这属于问题相对较小的那个。

一个能编译运行的例子如下:

extern crate tokio;
use core::future::Future;

fn handle(_a: &str) -> impl Future<Output = u32> + 'static {
    println!("{_a}");
    let s = "hello";
    async move {
        println!("{}", s);
        123123
    }
}

async fn make_service<F, Fut>(f: F)
where
    F: for<'b> Fn(&'b str) -> Fut + 'static,
    Fut: Future<Output = u32>,
{
    let s = "1".to_owned();
    println!("result = {}", f(s.as_str()).await);
}

#[tokio::main]
async fn main() {
    make_service(handle).await;
}

苦瓜小仔 2023-06-06 20:21

知识点就在 https://rustcc.cn/article?id=822e5659-4286-4bd5-a5ec-23793f2be833 帖子回复中,我给的三个链接里(我不想在各个地方重复解释相同的问题)

  • 你对 async fn 脱糖成 impl 形式有多熟?
  • 对生命周期省略规则有多熟?(比如这里的 impl Trait 和 dyn Trait 中的生命周期省略规则)
zylthinking 2023-06-06 17:49

首先, async fn handle(req: &str) -> u32 这种写法, 不会满足原型: for<'a> Fn(&'a str) -> Fut + Clone + 'static, 它只会认为返回的 future 捕获了 req; 若想表达其实没有捕获 req, 使用明确的语法, 别用语法糖。

其次, 你是真的捕获了 req, 你在 future 里面打印了 req

所以, 最大的问题并不是你的语法问题, 而是你切切实实写出了 bug; 自然, 看上去你语法其实也没搞明白, 但这属于问题相对较小的那个。

一个能编译运行的例子如下:

extern crate tokio;
use core::future::Future;

fn handle(_a: &str) -> impl Future<Output = u32> + 'static {
    println!("{_a}");
    let s = "hello";
    async move {
        println!("{}", s);
        123123
    }
}

async fn make_service<F, Fut>(f: F)
where
    F: for<'b> Fn(&'b str) -> Fut + 'static,
    Fut: Future<Output = u32>,
{
    let s = "1".to_owned();
    println!("result = {}", f(s.as_str()).await);
}

#[tokio::main]
async fn main() {
    make_service(handle).await;
}

1 共 5 条评论, 1 页