如何编写 Rust 通用 fn 或宏来从结构中提取特定字段?

问题描述 投票:0回答:1

我有几种建模为结构的资产类型,例如

#[derive(Debug, Deserialize, Serialize)]
struct Vehicle {
    short: String,
    name: String,
    number_plate: String,
    purchase_cost: u32,
    purchase_date: NaiveDate,
    charge_minute: f32,
    charge_km: f32,
}

不同的结构体有不同的字段,但它们都有一个实现 ToString 的“short”和“name”字段(实际上它们都是字符串)

我想获得(短,名称)对的 Vec,所以:

fn vehicle_pairs(vs: &Vec<Vehicle>) -> Vec<(String, String)> {
    vs.iter()
    .map(|v| (v.short.to_string(), v.name.to_string()))
    .collect::<Vec<_>>()
}

这很好。 为了将此函数推广到其他类型,我可能需要一个宏,因为为了使其通用,我需要指定与字段而不是方法相关的边界,我不相信这是可能的。

我是宏新手,今天刚刚阅读了一些文档。 我的第一次尝试:

macro_rules! pairs {
    ($T:ty) => {
        fn get_pairs<T>(xs: &Vec<T>) -> Vec<(String, String)> {
            xs.iter()
                .map(|x| (x.short.to_string(), x.name.to_string()))
                .collect::<Vec<_>>()
        }
    }
}

pairs!(Vehicle);

但这行不通。

如何创建一个通用函数,从具有这些字段的结构中提取(短,名称)?

rust
1个回答
0
投票

我认为在我们的尝试中,宏的通用方面和通用参数

<T>
之间存在混淆。

我理解您认为

get_pairs()
适用于具有两个成员 short
names
可转换为
String
something
序列。

首先,我会引入一个声明

get_pairs()
函数的特征。 然后宏可以帮助实现我们发现相关的任何序列。

#[derive(Debug)]
struct Vehicle {
    short: String,
    name: String,
    number_plate: String,
    purchase_cost: u32,
    charge_minute: f32,
    charge_km: f32,
}

trait GetPairs {
    fn get_pairs(&self) -> Vec<(String, String)>;
}

macro_rules! impl_getpairs_on_short_and_name {
    ($T:ty) => {
        impl GetPairs for [$T] {
            fn get_pairs(&self) -> Vec<(String, String)> {
                self.iter()
                    .map(|x| (x.short.to_string(), x.name.to_string()))
                    .collect::<Vec<_>>()
            }
        }
    };
}

impl_getpairs_on_short_and_name!(Vehicle);

fn main() {
    let vehicles =
        Vec::from_iter(["A", "B", "C"].into_iter().map(|n| Vehicle {
            short: format!("short_{}", n),
            name: format!("name_{}", n),
            number_plate: format!("plate_{}", n),
            purchase_cost: 0,
            charge_minute: 0.0,
            charge_km: 0.0,
        }));
    println!("vehicles: {:#?}", vehicles);
    let pairs = vehicles.get_pairs();
    println!("pairs: {:?}", pairs);
}
/*
vehicles: [
    Vehicle {
        short: "short_A",
        name: "name_A",
        number_plate: "plate_A",
        purchase_cost: 0,
        charge_minute: 0.0,
        charge_km: 0.0,
    },
    Vehicle {
        short: "short_B",
        name: "name_B",
        number_plate: "plate_B",
        purchase_cost: 0,
        charge_minute: 0.0,
        charge_km: 0.0,
    },
    Vehicle {
        short: "short_C",
        name: "name_C",
        number_plate: "plate_C",
        purchase_cost: 0,
        charge_minute: 0.0,
        charge_km: 0.0,
    },
]
pairs: [("short_A", "name_A"), ("short_B", "name_B"), ("short_C", "name_C")]
*/
© www.soinside.com 2019 - 2024. All rights reserved.