#enums #rust
#перечисления #Ржавчина
Вопрос:
Мне нужно сохранить вектор дискриминантов перечисления для сравнения:
use std::mem;
enum Thing {
Foo(usize),
Bar(usize, usize),
}
let ds: Vec<mem::Discriminant<Thing>> = vec![/* ??? */];
// ...
let thing: Thing = Foo(1234);
for d in ds.iter() {
if mem::discriminant(thing) == d {
println!("yay");
}
}
На практике, что произойдет, так это то, что макрос будет использоваться для генерации этого списка дискриминантов, чтобы соответствовать контексту в списке перечислений.
Например, у нас может быть что-то вроде этого:
enum Thing {
A(usize),
B(f32),
C(u8, u8, u8),
}
context_rule! {
A(a) B(b) C(c) B(d) : a b c < d => C(b * c)
}
Который должен генерировать вектор дискриминантов, соответствующих vec![A, B, C, B]
для проверки.
Ответ №1:
Я не думаю, что эта функциональность существует. Глядя на RFC (1 2) для дискриминантного API, он был разработан для довольно небольшого варианта использования.
При использовании перечисления ADT, которое содержит данные в некоторых вариантах, иногда желательно знать вариант, но игнорировать данные, чтобы сравнить два значения по варианту или сохранить варианты в хэш-карте, когда данные либо не хэшируются, либо неважны.
Учитывая это и ваш предполагаемый вариант использования, я бы предложил другой маршрут. Если вы хотите иметь вектор вещей, посмотрите, соответствуют ли элементы шаблону, и сделайте что-нибудь с данными; вы можете просто использовать сопоставление с шаблоном среза.
enum Thing {
A(usize),
B(usize),
C(usize, usize, usize),
}
fn main() {
use Thing::*;
let things = vec![A(0), B(1), C(2, 3, 4), B(5)];
let result = match things.as_slice() {
amp;[A(a), B(b), C(c, _, _), B(d)] if a b c < d => {
C(b * c, 0, 0)
}
_ => todo!("add fallback")
};
// do something with result
}
Сопоставление arm выглядит очень похоже на предложенный вами макрос.
Комментарии:
1. Это сопоставление шаблонов по срезу просто потрясающе. Это такой мощный язык. Спасибо!