< 返回版块

xbitlabs 发表于 2022-11-23 10:15

Tags:mismatched types

源码链接 https://files.cnblogs.com/files/xlabs/test.rar

error[E0308]: mismatched types

note: expected trait `for<'a> <for<'a> fn(&'a mut RequestCtx) -> impl Future<Output = hyper::Response<Body>> {Server::handle_not_found} as FnOnce<(&'a mut RequestCtx,)>>`
               found trait `for<'a> <for<'a> fn(&'a mut RequestCtx) -> impl Future<Output = hyper::Response<Body>> {Server::handle_not_found} as FnOnce<(&'a mut RequestCtx,)>>`

把下面这个trait的参数ctx:&mut RequestCtx改为ctx:RequestCtx是没有问题的,但是该如何改为ctx:&mut RequestCtx呢??

#[async_trait::async_trait]
pub trait HTTPHandler: Send + Sync + 'static {
    async fn handle(&self, ctx:&mut RequestCtx) -> Response;
}

评论区

写评论
作者 xbitlabs 2022-11-23 20:42

搞定了

--
👇
wangbyby: 所以,解决你的问题了吗

--
👇
xbitlabs: 好嘞,谢谢

--
👇
wangbyby: 下次建议提取最小用例哦

shanliu 2022-11-23 18:33

要简化语法用macro 干嘛要转为dyn object dyn 扯上生命周期 哎 反正我是受够了.

--
👇
xbitlabs: 哈哈,请指教

--
👇
shanliu: 这封装的. 哎. 当动态语言搞.

wangbyby 2022-11-23 17:52

所以,解决你的问题了吗

--
👇
xbitlabs: 好嘞,谢谢

--
👇
wangbyby: 下次建议提取最小用例哦

作者 xbitlabs 2022-11-23 17:50

好嘞,谢谢

--
👇
wangbyby: 下次建议提取最小用例哦

wangbyby 2022-11-23 17:48

下次建议提取最小用例哦

wangbyby 2022-11-23 17:47
fn handle_not_found(_ctx:&mut RequestCtx) -> impl Future<Output = Response> + Send + 'static{
    async{
        ResponseBuiler::with_status(hyper::StatusCode::NOT_FOUND)
    }
}

作者 xbitlabs 2022-11-23 17:46

哈哈,请指教

--
👇
shanliu: 这封装的. 哎. 当动态语言搞.

shanliu 2022-11-23 16:53

这封装的. 哎. 当动态语言搞.

shanliu 2022-11-23 16:51
use std::convert::Infallible;
use std::future::Future;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Instant;
use std::{collections::HashMap, pin::Pin};

use route_recognizer::{Params, Router as MethodRouter};

use hyper::service::{make_service_fn, service_fn};

macro_rules! register_method {
    ($method_name: ident, $method_def: expr) => {
        pub fn $method_name(&mut self, path: impl AsRef<str>, handler: impl HTTPHandler) {
            self.register($method_def, path, handler)
        }
    };
}

#[derive(Debug)]
pub struct Error(String);

impl Error {
    fn new(msg: impl ToString) -> Self {
        Error(msg.to_string())
    }
}

pub type HyperRequest = hyper::Request<hyper::Body>;
pub type Response = hyper::Response<hyper::Body>;

pub struct RequestCtx {
    pub request: HyperRequest,
    pub params: Params,
    pub remote_addr: SocketAddr,
}

pub struct ResponseBuiler;

impl ResponseBuiler {
    pub fn with_text(text: impl ToString) -> Response {
        hyper::Response::builder()
            .header(
                "Content-type".parse::<hyper::header::HeaderName>().unwrap(),
                "text/plain; charset=UTF-8"
                    .parse::<hyper::header::HeaderValue>()
                    .unwrap(),
            )
            .body(hyper::Body::from(text.to_string()))
            .unwrap()
    }

    pub fn with_html(text: impl ToString) -> Response {
        hyper::Response::builder()
            .header(
                "Content-type".parse::<hyper::header::HeaderName>().unwrap(),
                "text/html; charset=UTF-8"
                    .parse::<hyper::header::HeaderValue>()
                    .unwrap(),
            )
            .body(hyper::Body::from(text.to_string()))
            .unwrap()
    }

    pub fn with_status(status: hyper::StatusCode) -> Response {
        hyper::Response::builder()
            .status(status)
            .body(hyper::Body::empty())
            .unwrap()
    }
}

#[async_trait::async_trait]
pub trait HTTPHandler: Send + Sync + 'static {
    async fn handle(&self, ctx: &mut RequestCtx) -> Response;
}

type BoxHTTPHandler = Box<dyn HTTPHandler>;

#[async_trait::async_trait]
impl<F: Send + Sync + 'static, Fut> HTTPHandler for F
where
    F: Fn(&mut RequestCtx) -> Fut,
    Fut: Future<Output = Response> + Send + 'static,
{
    async fn handle(&self, ctx: &mut RequestCtx) -> Response {
        self(ctx).await
    }
}

type Router = HashMap<String, MethodRouter<BoxHTTPHandler>>;

#[async_trait::async_trait]
pub trait Middleware: Send + Sync + 'static {
    async fn handle<'a>(&'a self, ctx: &mut RequestCtx, next: Next<'a>) -> Response;
}

#[allow(missing_debug_implementations)]
pub struct Next<'a> {
    pub(crate) endpoint: Pin<Box<&'a dyn HTTPHandler>>,
    pub(crate) next_middleware: &'a [Arc<dyn Middleware>],
}

impl<'a> Next<'a> {
    /// Asynchronously execute the remaining middleware chain.
    pub async fn run(mut self, ctx: &mut RequestCtx) -> Response {
        if let Some((current, next)) = self.next_middleware.split_first() {
            self.next_middleware = next;
            current.handle(ctx, self).await
        } else {
            (self.endpoint).handle(ctx).await
        }
    }
}

pub struct AccessLog;

#[async_trait::async_trait]
impl Middleware for AccessLog {
    async fn handle<'a>(&'a self, ctx: &mut RequestCtx, next: Next<'a>) -> Response {
        let start = Instant::now();
        let method = ctx.request.method().to_string();
        let path = ctx.request.uri().path().to_string();
        let remote_addr = ctx.remote_addr;
        let res = next.run(ctx).await;
        println!(
            "{} {:?} {} {} {}ms",
            method,
            path,
            res.status().as_str(),
            remote_addr,
            start.elapsed().as_millis()
        );
        res
    }
}

pub struct Server {
    router: Router,
    middlewares: Vec<Arc<dyn Middleware>>,
}

impl Server {
    pub fn new() -> Self {
        Server {
            router: HashMap::new(),
            middlewares: Vec::new(),
        }
    }

    pub fn register(
        &mut self,
        method: impl ToString,
        path: impl AsRef<str>,
        handler: impl HTTPHandler,
    ) {
        let method = method.to_string().to_uppercase();
        self.router
            .entry(method)
            .or_insert_with(MethodRouter::new)
            .add(path.as_ref(), Box::new(handler));
    }
    pub fn get(&mut self, path: impl AsRef<str>, handler: impl HTTPHandler) {
        let method = "GET".to_string().to_uppercase();
        self.router
            .entry(method)
            .or_insert_with(MethodRouter::new)
            .add(path.as_ref(), Box::new(handler));
    }
    // register_method!(get, "GET");
    register_method!(head, "HEAD");
    register_method!(post, "POST");
    register_method!(put, "PUT");
    register_method!(delete, "DELETE");
    register_method!(connect, "CONNECT");
    register_method!(options, "OPTIONS");
    register_method!(trace, "TRACE");
    register_method!(patch, "PATCH");

    pub fn middleware(&mut self, middleware: impl Middleware) {
        self.middlewares.push(Arc::new(middleware));
    }

    pub async fn run(self, addr: SocketAddr) -> Result<(), Error> {
        let Self {
            router,
            middlewares,
        } = self;

        let router = Arc::new(router);
        let middlewares = Arc::new(middlewares);

        let make_svc = make_service_fn(|conn: &hyper::server::conn::AddrStream| {
            let router = router.clone();
            let middlewares = middlewares.clone();
            let remote_addr = conn.remote_addr();

            async move {
                Ok::<_, Infallible>(service_fn(move |req: HyperRequest| {
                    let router = router.clone();
                    let middlewares = middlewares.clone();

                    async move {
                        let method = &req.method().as_str().to_uppercase();
                        let def: Pin<Box<&dyn HTTPHandler>> = Box::pin(&Self::handle_not_found);
                        let mut req_params = Params::new();
                        let endpoint = match router.get(method) {
                            Some(router) => match router.recognize(req.uri().path()) {
                                Ok(route_recognizer::Match { handler, params }) => {
                                    req_params = params;
                                    let t = Box::pin(&**handler);
                                    t
                                }
                                Err(_) => def,
                            },
                            None => def,
                        };

                        let next = Next {
                            endpoint,
                            next_middleware: &middlewares,
                        };

                        let mut ctx = RequestCtx {
                            request: req,
                            params: req_params,
                            remote_addr,
                        };

                        let resp = next.run(&mut ctx).await;

                        Ok::<_, Infallible>(resp)
                    }
                }))
            }
        });

        let server = hyper::Server::bind(&addr).serve(make_svc);

        server
            .await
            .map_err(|e| Error::new(format!("server run error: {:?}", e)))?;

        Ok(())
    }

    fn handle_not_found(
        _ctx: &mut RequestCtx,
    ) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>> {
        let tmp = ResponseBuiler::with_status(hyper::StatusCode::NOT_FOUND);
        Box::pin(async move { tmp })
    }
}

impl Default for Server {
    fn default() -> Self {
        Self::new()
    }
}

Grobycn 2022-11-23 16:06

改了之后报什么错误

--
👇
xbitlabs: 改成这样也没有用

--
👇
Grobycn: 你修改一下函数啊, 改成这样:

fn handle_not_found(ctx: &mut RequestCtx) -> impl Future<Output = Response> + Send + 'static
作者 xbitlabs 2022-11-23 14:26

改成这样也没有用

--
👇
Grobycn: 你修改一下函数啊, 改成这样:

fn handle_not_found(ctx: &mut RequestCtx) -> impl Future<Output = Response> + Send + 'static
Grobycn 2022-11-23 14:12

你修改一下函数啊, 改成这样:

fn handle_not_found(ctx: &mut RequestCtx) -> impl Future<Output = Response> + Send + 'static
作者 xbitlabs 2022-11-23 11:43

handle_not_found不是trait,是一个已经实现了的函数,应该没法这样加吧

--
👇
Grobycn: 类型不匹配,这里指的是 FnOnce::Output 两个不匹配 先看看impl HTTPHandler for F 对 F 的要求:

where
      F: Fn(&mut RequestCtx) -> Fut,
      Fut: Future<Output = Response> + Send + 'static,

再看一下 handle_not_found 的函数签名:

Fn(&mut RequestCtx) -> impl Future<Output = Response>

这里编译器推断不出来Send + 'static,故报错 加上 Send'static,可以通过编译

Grobycn 2022-11-23 11:13

类型不匹配,这里指的是 FnOnce::Output 两个不匹配 先看看impl HTTPHandler for F 对 F 的要求:

where
      F: Fn(&mut RequestCtx) -> Fut,
      Fut: Future<Output = Response> + Send + 'static,

再看一下 handle_not_found 的函数签名:

Fn(&mut RequestCtx) -> impl Future<Output = Response>

这里编译器推断不出来Send + 'static,故报错 加上 Send'static,可以通过编译

1 共 14 条评论, 1 页