首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何通过迭代路径向量来设置路由

如何通过迭代路径向量来设置路由
EN

Stack Overflow用户
提问于 2017-01-03 16:05:06
回答 1查看 315关注 0票数 0

轮轨你好世界示例演示如何对固定的路由集使用router!宏。

下面的示例代码说明了需要能够从数据库或可插拔代码中“引导”路由--这是我目前能够使用Iron web框架实现的:

代码语言:javascript
复制
pub struct Route {
    pub http_method: String,
    pub url_path: String,
    pub callback_func: fn(_: &mut Request) -> IronResult<Response>,
}

impl Route {
    pub fn new(m: String, u: String, f: fn(_: &mut Request) -> IronResult<Response>) -> Route {
        Route {
            http_method: m,
            url_path: u,
            callback_func: f,
        }
    }
}

fn main() {
    // router is an Iron middleware
    let mut router = Router::new();

    // prepare routes for bootstrapping into the Iron router
    let r1 = Route::new("get".to_string(), "/*".to_string(), my_callback_func);
    let r2 = Route::new("get".to_string(), "/".to_string(), my_callback_func);

    let mut routes = Vec::new();
    routes.push(r1);
    routes.push(r2);

    for route in routes.iter_mut() {
        if route.http_method == "get" {
            // passes each route to the Iron router
            router.get(&route.url_path, (&*route).callback_func);
        } // else if, put, post, delete...
    }

    Iron::new(router).http("localhost:3000").unwrap();
}

fn my_callback_func(_: &mut Request) -> IronResult<Response> {
    //...
}

(游乐场)

尽管我正在阅读Rust中的宏,但我对、Rust或宏没有足够的理解,无法理解如何实现与Rust的等价。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-01-06 03:07:07

如果您检查,它很长,但并不是非常复杂:

代码语言:javascript
复制
($request:expr, $(($method:ident) ($($pat:tt)+) => $value:block,)* _ => $def:expr) => {
    {
        let request = &$request;

        // ignoring the GET parameters (everything after `?`)
        let request_url = request.url();
        let request_url = {
            let pos = request_url.find('?').unwrap_or(request_url.len());
            &request_url[..pos]
        };

        let mut ret = None;

        $({
            if ret.is_none() && request.method() == stringify!($method) {
                ret = router!(__check_pattern request_url $value $($pat)+);
            }
        })+

        if let Some(ret) = ret {
            ret
        } else {
            $def
        }
    }
};

换句话说,它需要一个请求、零个或多个模式来匹配,以及一个默认模式。它获取URL,然后分派到宏的另一个分支,以查看URL是否匹配路径,并执行一些递归的技巧来定义带有路径组件的一些变量。无论哪个arm首先匹配,都将设置返回值,如果没有匹配,则将使用默认值。

不幸的是,宏期望ident用于方法和路径,因此基本上不能将其与表达式一起使用。这意味着我们不能传入像"foo"这样的变量或文字。这对你来说很难。

所以,我们做的是所有优秀的程序员所做的事情:复制和粘贴代码。从宏中取出块并重新使用它们:

代码语言:javascript
复制
#[macro_use]
extern crate rouille;

use rouille::Request;
use rouille::Response;

struct Route(&'static str, &'static str, fn(&Request) -> Response);

fn main() {
    let routes = [
        Route("GET", "/one", do_one),
        Route("GET", "/two", do_two),
    ];

    rouille::start_server("0.0.0.0:9080", move |request| {
        let mut result = None;

        let request = &request;

        // ignoring the GET parameters (everything after `?`)
        let request_url = request.url();
        let request_url = {
            let pos = request_url.find('?').unwrap_or(request_url.len());
            &request_url[..pos]
        };

        for &Route(method, path, f) in &routes {
            if result.is_none() {
                // This checking of the path is terrible, limited, and hacky
                if request.method() == method && request_url.ends_with(path) {
                    result = Some(f(request));
                }
            }
        }

        result.unwrap_or_else(|| Response::text("Default!"))
    });
}

fn do_one(_: &Request) -> Response {
    Response::text("hello world one")
}

fn do_two(_: &Request) -> Response {
    Response::text("hello world two")
}

这将为/one/two和其他一切运行各种处理程序。

我不是轮轨方面的专家,事实上我以前从来没有用过它,但是看起来你确实是在尝试用它来做一些超出目前设计目的的事情。也许这是故意的,作者试图提出一个非常固执己见的工具。也许这是偶然的,他们还没有想到这个用例。也许这是暂时的,他们只是还没来得及解决。

不管怎样,我建议问问作者。如果这不是预期的用例,他们可以更新项目文档以明确声明。否则,它们可能会产生问题来实现该特性,并且您可能会帮助设计它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41447550

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档