【问题标题】:Rust showing expected trait object `dyn Future`, found opaque type when passing function as a paramRust 显示预期的特征对象`dyn Future`,在将函数作为参数传递时发现不透明类型
【发布时间】:2021-05-25 06:28:22
【问题描述】:
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::time::Duration;

// pyO3 module
use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

use std::future::Future;

#[pyfunction]
pub fn start_server() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    let pool = ThreadPool::new(4);

    for stream in listener.incoming() {
        let stream = stream.unwrap();

        pool.execute(|| {
            let rt = tokio::runtime::Runtime::new().unwrap();
            handle_connection(stream, rt, &test_helper);
        });
    }
}

#[pymodule]
pub fn roadrunner(_: Python<'_>, m: &PyModule) -> PyResult<()> {
    m.add_wrapped(wrap_pyfunction!(start_server))?;
    Ok(())
}

async fn read_file(filename: String) -> String {
    let con = tokio::fs::read_to_string(filename).await;
    con.unwrap()
}

async fn test_helper(contents: &mut String, filename: String) {
    // this function will accept custom function and return
    *contents = tokio::task::spawn(read_file(filename.clone()))
        .await
        .unwrap();
}

pub fn handle_connection(
    mut stream: TcpStream,
    runtime: tokio::runtime::Runtime,
    test: &dyn Fn(&mut String, String) -> (dyn Future<Output = ()> + 'static),
) {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();

    let get = b"GET / HTTP/1.1\r\n";
    let sleep = b"GET /sleep HTTP/1.1\r\n";

    let (status_line, filename) = if buffer.starts_with(get) {
        ("HTTP/1.1 200 OK", "hello.html")
    } else if buffer.starts_with(sleep) {
        thread::sleep(Duration::from_secs(5));
        ("HTTP/1.1 200 OK", "hello.html")
    } else {
        ("HTTP/1.1 404 NOT FOUND", "404.html")
    };

    let mut contents = String::new();
    let future = test_helper(&mut contents, String::from(filename));
    runtime.block_on(future);

    let response = format!(
        "{}\r\nContent-Length: {}\r\n\r\n{}",
        status_line,
        contents.len(),
        contents
    );

    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

我正在尝试创建一个需要将异步函数作为参数传递的模块。我已经通过了元素,但我无法从错误消息中推断出我应该做什么。它告诉我类型推断存在一些不匹配。

这是我收到的错误消息cargo check

error[E0271]: type mismatch resolving `for<'r> <for<'_> fn(&mut String, String) -> impl Future {test_helper} as FnOnce<(&'r mut String, String)>>::Output == (dyn Future<Output = ()> + 'static)`
   --> src/lib.rs:124:43
    |
124 |             handle_connection(stream, rt, &test_helper);
    |                                           ^^^^^^^^^^^^ expected trait object `dyn Future`, found opaque type
...
140 | async fn test_helper(contents: &mut String, filename: String) {
    |                                                               - checked the `Output` of this `async fn`, found opaque type
    |
    = note: while checking the return type of the `async fn`
    = note: expected trait object `(dyn Future<Output = ()> + 'static)`
                found opaque type `impl Future`
    = note: required for the cast to the object type `dyn for<'r> Fn(&'r mut String, String) -> (dyn Future<Output = ()> + 'static)`

error: aborting due to previous error

请让我知道应该在此处进行哪些更改。提前致谢。

【问题讨论】:

    标签: asynchronous rust async-await future pyo3


    【解决方案1】:

    您正在编写一个返回 dyn 类型的函数类型,而不是对它的引用,而是未调整大小的类型本身,这是不可能的。每次你想写这样的东西时,试着用泛型代替:

    pub fn handle_connection<F>(
        mut stream: TcpStream,
        runtime: tokio::runtime::Runtime,
        test: &dyn Fn(&mut String, String) -> F,
    )
    where F: Future<Output = ()> + 'static
    

    现在失败并出现这个奇怪的错误:

    error[E0308]: mismatched types
      --> src/lib.rs:19:43
       |
    19 |             handle_connection(stream, rt, &test_helper);
       |                                           ^^^^^^^^^^^^ one type is more general than the other
       |
       = note: expected associated type `<for<'_> fn(&mut String, String) -> impl Future {test_helper} as FnOnce<(&mut String, String)>>::Output`
                  found associated type `<for<'_> fn(&mut String, String) -> impl Future {test_helper} as FnOnce<(&mut String, String)>>::Output`
    

    但这也是意料之中的,你的未来会引用你正在传递的&amp;mut String,所以它不再是'static。解决方案就是添加一个生命周期的泛型参数:

    pub fn handle_connection<'a, F>(
        mut stream: TcpStream,
        runtime: tokio::runtime::Runtime,
        test: &dyn Fn(&'a mut String, String) -> F,
    )
    where F: Future<Output = ()> + 'a
    

    现在它应该可以编译了。

    【讨论】:

    • 嗨@rodrigo。谢谢你的解释。但我不明白使用泛型而不是单一责任返回类型有什么区别?带有说明符的泛型如何工作而不是确切的返回类型?
    • @SanskarJethi:因为dyn T 类型不是精确类型,它是一个无大小类型,你必须使用某种引用或Box来解决它。 async fn 的实际返回类型是未命名的,不能直接输入,但是使用泛型可以让编译器进行推导并返回确切的类型。
    猜你喜欢
    • 2022-01-20
    • 2022-08-17
    • 2022-11-20
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-21
    相关资源
    最近更新 更多