我正在为我的一个项目创建一个Bit enum,我经历了与as u32
(或任何其他类型)语法的一些奇怪的交互.我有Into u8,u16,.. u128为我的Bit enum实现,所以我在测试中无意地使用了Bit as u32
,有点假设它是.into()
的语法糖.我运行了一些失败的测试,试图找到我发现的错误,我的Bit enum是这样布局的:
pub enum Bit {
On,
Off,
}
我一时兴起将其改为:
pub enum Bit {
Off,
On,
}
没多想.我重新运行了测试,看看哪个测试再次失败,令我惊讶的是,另外2个测试通过了!
我做了一些额外的挖掘,来回切换On
和Off
,并将as u32
更改为.into()
呼叫.as u32
似乎完全忽略了任何Into实现,只是转换比特.这有点道理,但例如u32 as f64
如何工作?您不能简单地在那里转换位.它到底是做什么的?
看看suggested question,我的Enum似乎正在使用TryFrom
实现(这也是实现的).但这对我来说没有意义,为什么rust会使用TryFrom
实现,而这可能会对具体实现的Into
感到panic ?但即使这样的解释也没有意义,因为TryFrom
实现专门将0映射到Bit::Off、1映射到Bit::On以及所有其他值映射到错误.
通常我会查看相关文档,但我不知道在哪里可以找到相关文档,因为它更多的是一种语言功能,而不是某个东西的实现,指向该功能的指针也有帮助!
作为参考,这是我使用as u32
的地方:
fn bits_flipped(left: &BitString, right: &BitString) -> u32 {
assert_eq!(
left.len(),
right.len(),
"the length of the bitstrings is not equal. Left is {} and right is {}",
left.len(),
right.len()
);
let mut difference: u32 = 0;
for i in 0..left.len() {
difference += (left[i] ^ right[i]) as u32; // This line was causing issues
}
difference
}
这是我用于Into
实现的宏:
macro_rules! bit_into_type {
($t:ty) => {
impl Into<$t> for Bit {
#![allow(clippy::from_over_into)]
fn into(self) -> $t {
match self {
Self::On => 1,
Self::Off => 0,
}
}
}
};
}
最后,这是我用于TryFrom
实现的宏:
macro_rules! bit_try_from {
($t:ty) => {
impl TryFrom<$t> for Bit {
type Error = String;
fn try_from(value: $t) -> Result<Self, Self::Error> {
match value {
0 => Ok(Bit::Off),
1 => Ok(Bit::On),
value => Err(format!("Cannot represent {} as a single bit", value)),
}
}
}
};
}