我有以下代码,我需要在排名之间进行直接比较。例如,我需要能够做到self as u8 + 1 == other as u8
。
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum Rank {
Ace = 1,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
}
impl TryFrom<u8> for Rank {
type Error = ();
// TODO: replace with macro or find better option
fn try_from(v: u8) -> Result<Self, Self::Error> {
match v {
x if x == Rank::Ace as u8 => Ok(Rank::Ace),
x if x == Rank::Two as u8 => Ok(Rank::Two),
x if x == Rank::Three as u8 => Ok(Rank::Three),
x if x == Rank::Four as u8 => Ok(Rank::Four),
x if x == Rank::Five as u8 => Ok(Rank::Five),
x if x == Rank::Six as u8 => Ok(Rank::Six),
x if x == Rank::Seven as u8 => Ok(Rank::Seven),
x if x == Rank::Eight as u8 => Ok(Rank::Eight),
x if x == Rank::Nine as u8 => Ok(Rank::Nine),
x if x == Rank::Ten as u8 => Ok(Rank::Ten),
x if x == Rank::Jack as u8 => Ok(Rank::Jack),
x if x == Rank::Queen as u8 => Ok(Rank::Queen),
x if x == Rank::King as u8 => Ok(Rank::King),
_ => Err(()),
}
}
}
Run Code Online (Sandbox Code Playgroud)
有没有更有效的方法来编写这个而不使用宏并且基本上将其全部写出来?
tl;dr:是的,有一种方法可以在不使用宏的情况下做到这一点,但它不安全。宏没问题;使用num_enum代替。
如果您愿意深入研究不安全代码的领域,您可以使用std::mem::transmute()
将 转换u8
为Rank
:
fn try_from(v: u8) -> Result<Self, Self::Error> {
match v {
x if x >= Rank::Ace as u8 && x <= Rank::King as u8 =>
Ok(unsafe { std::mem::transmute(x) }),
_ => Err(()),
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果枚举值稍后发生更改并且x >= Rank::Ace as u8 && x <= Rank::King as u8
不再保证该值是有效的枚举值,则在转换错误值时将导致未定义的行为。
如果您采用这种方法,我会在 的定义上添加非常明显的警告注释,Rank
以便其他人(以及未来的您)知道在没有适当更新实现的情况下更改值try_from
可能会导致 UB。
transmute
非常不安全。有很多方法会导致此函数出现未定义的行为。transmute
应该是绝对的最后手段。
这是节省 11-12 行代码的权衡,但代价是以后可能会破坏自己。我给出这个答案是为了完整起见,是为了说“是的,有一种方法可以满足您的要求,但您确实不应该这样做。 ”
归档时间: |
|
查看次数: |
3410 次 |
最近记录: |