< 返回版块

招宝进财 发表于 2022-03-16 20:10

Tags:macro, recursion


macro_rules! top_level_service_fn {
    (
        $name:ident, GET
    ) => {
        top_level_service_fn!(
            $name,
            GET
        );
    };

    (
        $name:ident, $method:ident
    ) => {
        top_level_service_fn!(
            #[doc = concat!("Route `", stringify!($method) ,"` requests to the given service.")]
            ///
            /// See [`get_service`] for an example.
            $name,
            $method
        );
    };

    (
        $(#[$m:meta])+
        $name:ident, $method:ident
    ) => {
        $(#[$m])+
        pub fn $name<S, ReqBody, ResBody>(svc: S) -> MethodRouter<ReqBody, S::Error>
        where
            S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
            S::Future: Send + 'static,
            ResBody: HttpBody<Data = Bytes> + Send + 'static,
            ResBody::Error: Into<BoxError>,
        {
            on_service(MethodFilter::$method, svc)
        }
    };
}

求教: 第一个匹配分支为啥不会无限递归?

评论区

写评论
作者 招宝进财 2022-03-22 14:24

多谢多谢, 我实操研究一下. 我对宏的了解还不多.

--
👇
苦瓜小仔: 我不知道你对(声明)宏了解多少,因为宏的知识涉及很多细节,一两句话是解释不了的(最好的办法就是自己去写,然后理解你所见所写的宏代码)。

此外,你这句话,我觉得有两个问题:

  1. 第一个分支的 GET 笼统地说是一个标记,而不是字面值(Literal 在 Rust 是专用术语)
  2. GET 在第一个分支的匹配部分 (matcher) 中是一个具体的标记(至于是否按照 $ident 还是 $tt 这类标记去捕获,我不知道 ),一旦第一分支的展开部分(或者叫 transcriber)也匹配成功,则进入第三分支,此时 GET 被当作 标识符 进行语法解析

https://zjp-cn.github.io/tlborm/macros/syntax/source-analysys.html

--
👇
招宝进财: 也就是说第一个分支的GET是个字面量, 在第一个分支内被转成了标识符?

munpf 2022-03-22 13:26

你这个代码没有放全啊,原代码的第一个分支还有那么长的文档注释没放上来。

苦瓜小仔 2022-03-22 13:01

我不知道你对(声明)宏了解多少,因为宏的知识涉及很多细节,一两句话是解释不了的(最好的办法就是自己去写,然后理解你所见所写的宏代码)。

此外,你这句话,我觉得有两个问题:

  1. 第一个分支的 GET 笼统地说是一个标记,而不是字面值(Literal 在 Rust 是专用术语)
  2. GET 在第一个分支的匹配部分 (matcher) 中是一个具体的标记(至于是否按照 $ident 还是 $tt 这类标记去捕获,我不知道 ),一旦第一分支的展开部分(或者叫 transcriber)也匹配成功,则进入第三分支,此时 GET 被当作 标识符 进行语法解析

https://zjp-cn.github.io/tlborm/macros/syntax/source-analysys.html

--
👇
招宝进财: 也就是说第一个分支的GET是个字面量, 在第一个分支内被转成了标识符?

作者 招宝进财 2022-03-22 10:20

也就是说第一个分支的GET是个字面量, 在第一个分支内被转成了标识符?

苦瓜小仔 2022-03-16 21:15

你自己写个例子,然后 cargo expand 就知道了:playground

原始代码在这:top_level_service_fn

第一个分支的展开结果是进入第三分支,所以不会无限递归。(///#[doc = ""] 的语法糖)

        top_level_service_fn!(
            /// Route `GET` requests to the given service.
            ///
            /// # Example
            ///
            /// ```rust
            /// use axum::{
            ///     http::Request,
            ///     Router,
            ///     routing::get_service,
            /// };
            /// use http::Response;
            /// use std::convert::Infallible;
            /// use hyper::Body;
            ///
            /// let service = tower::service_fn(|request: Request<Body>| async {
            ///     Ok::<_, Infallible>(Response::new(Body::empty()))
            /// });
            ///
            /// // Requests to `GET /` will go to `service`.
            /// let app = Router::new().route("/", get_service(service));
            /// # async {
            /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
            /// # };
            /// ```
            ///
            /// Note that `get` routes will also be called for `HEAD` requests but will have
            /// the response body removed. Make sure to add explicit `HEAD` routes
            /// afterwards.
            $name,
            GET
        );
1 共 5 条评论, 1 页