#rust
#Ржавчина
Вопрос:
Я всегда готов найти лучшее решение с наилучшей производительностью в моем программном обеспечении. Итак, я хотел бы спросить, есть ли лучший вариант для решения моей проблемы.
У меня есть определенное перечисление
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
#[derive(serde::Serialize, serde::Deserialize)]
#[derive(strum_macros::EnumString, strum_macros::Display)]
pub enum CarMotive {
Standard = 0,
Deluxe = 1,
Sport = 2,
}
И у меня есть вектор строк ["standard","deluxe"]
, который поступает из файла csv.
Я хотел бы проверить совпадения между вектором и перечислениями.
В случае отсутствия «совпадения» укажите ошибку для каждого параметра перечисления.
Я решил это таким образом. У меня есть функция для каждого параметра перечисления, и в случае отсутствия совпадения у меня есть функция, которая возвращает ошибку.
Мотив 1:
pub fn find_standard(
dataset: amp;[String],
) -> Result<(), Box<dyn std::error::Error>> {
match dataset.iter().find(|amp;m| {
let car_motive = CarMotive::from_str(amp;m.motive);
if car_motive == Ok(CarMotive::Standard) {
true
} else {
false
}
}) {
Some(_x) => (),
None => print_an_error(amp;format!(
"CarMotive:Standard Motive missing in vector"
)),
}
Ok(())
}
Мотив 2:
pub fn find_deluxe(
dataset: amp;[String],
) -> Result<(), Box<dyn std::error::Error>> {
match dataset.iter().find(|amp;m| {
let car_motive = CarMotive::from_str(amp;m.motive);
if car_motive == Ok(CarMotive::Deluxe) {
true
} else {
false
}
}) {
Some(_x) => (),
None => print_an_error(amp;format!(
"CarMotive:Deluxe Motive missing in vector"
)),
}
Ok(())
}
Мотив 3:
pub fn find_sport(
dataset: amp;[String],
) -> Result<(), Box<dyn std::error::Error>> {
match dataset.iter().find(|amp;m| {
let car_motive = CarMotive::from_str(amp;m.motive);
if car_motive == Ok(CarMotive::Sport) {
true
} else {
false
}
}) {
Some(_x) => (),
None => print_an_error(amp;format!(
"CarMotive:Sport Motive missing in vector"
)),
}
Ok(())
}
И способ, которым я должен это протестировать:
#[test]
#[serial]
fn find_standard_nok() {
let dataset = vec!["deluxe".to_string()];
let mut s_err = String::new();
{
let mut err_ssh = shh::stderr().unwrap();
find_standard(amp;dataset).unwrap();
let _ = err_ssh.read_to_string(amp;mut s_err).unwrap();
}
assert_eq!(s_err, ""CarMotive:Standard Motive missing in vector"n");
}
Я думаю, что у него не самая лучшая производительность, потому что он «перебирает» набор данных 3 раза.
В случае, если перечисление увеличивается, я должен добавить еще одну функцию для проверки соответствия.
У меня есть опыт работы с интерфейсом, и мне иногда бывает трудно решать подобные функции. Заранее спасибо.
Комментарии:
1. Я не понимаю, что вы говорите, говоря «это цикл набора данных 3 раза». Ваши
find
функции просматривают весь ввод, потому что они пытаются найти, есть ли у ввода вариант (кстати, на самом деле не имеет никакого смысла, что они возвращают мне что-либо, кроме не булевых значений), но если вы просто хотите просмотреть набор данных один раз, вы можете … просто сопоставитьCarMotive::from_str
входные данные, а затем найтичто вам нужно для результата с помощью scan или find или fold?2. Кстати, помимо возвращаемых типов, которые я нахожу глубоко неподходящими, ваш код немного странный, например
if car_motive == Ok(CarMotive::Standard) { true } else { false }
, простоcar_motive == Ok(CarMotive::Standard)
.3. Также вы можете передать искомый вариант в свой finder вместо того, чтобы кодировать одну и ту же функцию 3 раза.
Ответ №1:
Один из способов получить что-то вроде того, что вы просите, а также деупликировать ваши функции — это просмотреть ваши данные и отслеживать уникальные enum
значения, которые вы видели, вот так:
pub fn find_matches(dataset: amp;[String]) -> HashSet<CarMotive> {
let mut matches = HashSet::new();
dataset.iter().for_each(|m| {
if let Ok(car_motive) = CarMotive::from_str(amp;m) {
matches.insert(car_motive);
}
});
return matches;
}