【发布时间】:2023-01-18 00:29:38
【问题描述】:
我正在制作一个 Web API 客户端。我想创建对应于可用 API 端点的函数。
在某些情况下,URL 始终相同。然后,手动调用 API 如下所示:
let things_list_url = "https://example.com/api/things/list";
let things_list: Vec<SomeThing> = make_request(GET, thing_list_url).into();
我为此使用的宏如下所示:
macro_rules! api_request {
($name: ident, $method: ident, $path: expr, $return_type: ty) => {
pub fn $name() -> $return_type {
let action_url = format!("https://example.com/api{}", $path);
let action_result = make_request($method, action_url);
action_result.into()
}
};
}
api_request!(get_things_list, GET, "/things/list", Vec<SomeThing>);
fn main() {
println!("{:?}", get_things_list());
}
只要 URL 保持不变,类似的模式适用于 API 调用有主体的情况。
其他一些端点在其 URL 中有参数。手动调用它们看起来像:
let thing = SomeThing { id: 123, ...};
let thing_status_url = format!("https://example.com/api/things/{}/status", thing.id);
let thing_status: SomeThingStatus = make_request(GET, thing_status_url).into();
但是,我为此制作宏的尝试不起作用。为简单起见,我们假设 format! 调用只有一个参数:
macro_rules! api_request_with_path {
($name: ident, $method: ident, $request_type: ty, $return_type: ty, $path_format_string: expr, $path_format_arg: expr) => {
pub fn $name(
arg: $request_type
) -> $return_type {
let action_url_fragment = format!($path_format_string, $path_format_arg);
let action_url = format!("https://example.com/api{}", action_url_fragment);
let action_result = make_request($method, action_url);
action_result.into()
}
};
}
api_request_with_path!(get_thing_status, GET, SomeThing, SomeThingStatus, "things/{}/status", arg.id);
这失败了,因为我正在传递一个包含 arg 的表达式——生成函数的参数——但是 arg 在宏调用所在的范围内不存在。
我怎样才能为宏提供一种将 $request_type 类型的参数转换为 URL 字符串的方法?
【问题讨论】: