轮轨你好世界示例演示如何对固定的路由集使用router!宏。
下面的示例代码说明了需要能够从数据库或可插拔代码中“引导”路由--这是我目前能够使用Iron web框架实现的:
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的等价。
发布于 2017-01-06 03:07:07
如果您检查宏,它很长,但并不是非常复杂:
($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"这样的变量或文字。这对你来说很难。
所以,我们做的是所有优秀的程序员所做的事情:复制和粘贴代码。从宏中取出块并重新使用它们:
#[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和其他一切运行各种处理程序。
我不是轮轨方面的专家,事实上我以前从来没有用过它,但是看起来你确实是在尝试用它来做一些超出目前设计目的的事情。也许这是故意的,作者试图提出一个非常固执己见的工具。也许这是偶然的,他们还没有想到这个用例。也许这是暂时的,他们只是还没来得及解决。
不管怎样,我建议问问作者。如果这不是预期的用例,他们可以更新项目文档以明确声明。否则,它们可能会产生问题来实现该特性,并且您可能会帮助设计它。
https://stackoverflow.com/questions/41447550
复制相似问题