如何将动态数量的类型参数传递给函数?

时间:2014-10-24 20:22:01

标签: rust

让我们说我想为HTTP API编写一个小客户端。它有一个返回汽车列表的资源:

GET /cars

它还接受两个可选的查询参数colormanufacturer,因此我可以查询特定的汽车:

GET /cars?color=black
GET /cars?manufacturer=BMW
GET /cars?color=green&manufacturer=VW

如何在Rust中正确公开这些资源?由于Rust不支持重载,因此定义多个函数似乎是常用的方法,例如:

fn get_cars() -> Cars
fn get_cars_by_color(color: Color) -> Cars
fn get_cars_by_manufacturer(manufacturer: Manufacturer) -> Cars
fn get_cars_by_manufacturer_and_color(manufacturer: Manufacturer, color: Color) -> Cars

但是当你有多个参数时,这显然不会扩展。

另一种方法是使用结构:

struct Parameters {
    color: Option<Color>,
    manufacturer: Option<Manufacturer>
}

fn get_cars(params: Parameters) -> Cars

这具有相同的缩放问题,必须在创建时设置每个结构字段(即使其值仅为None)。

我想我可以接受一个HashMap<String, String>,但这听起来也不是很好。 所以我的问题是,在Rust中执行此操作的正确/最佳方法是什么?

2 个答案:

答案 0 :(得分:4)

您可以使用Builder pattern,如上所述here。对于您的特定API,它可能如下所示:

Cars::new_get()
    .by_color("black")
    .by_manufacturer("BMW")
    .exec();

答案 1 :(得分:1)

我想指出的是,无论解决方案如何,如果您希望编译时检查解决方案,“url解析 - &gt;编译时可检查”转换必然是硬连线的。您可以使用外部脚本,宏等等生成它...但无论如何编译器要检查它,它必须在编译时存在。没有捷径。

因此,无论你选择哪种API,在某些时候你都会有类似的东西:

fn parse_url(url: &str) -> Parameters {
    let mut p: Parameters = { None, None };

    if let Some(manufacturer) = extract("manufacturer", url) {
        p.manufacturer = Some(Manufacturer::new(manufacturer));
    }
    if let Some(color) = extract("color", url) {
        p.color = Some(Color::new(color));
    }

    p
}

虽然你可以试试看它,但基本面不会改变。