Я создавал перечисление Bit для своего проекта и столкнулся с каким-то странным взаимодействием с синтаксисом as u32 (или любого другого типа). У меня есть Into<u8, u16, .. u128>, реализованный для моего перечисления Bit, поэтому я бездумно использовал Bit as u32 в своем тесте, как бы предполагая, что это синтаксический сахар для .into(). Я провел несколько тестов, которые не увенчались успехом, пытаясь найти ошибку, которую я обнаружил в том, что мое перечисление Bit было расположено следующим образом:
pub enum Bit {
On,
Off,
}
По прихоти я изменил его на:
pub enum Bit {
Off,
On,
}
Ничего об этом не думая. Я повторно запустил свои тесты, чтобы увидеть, какой тест снова не прошел, и, к моему удивлению, два дополнительных теста прошли успешно!
Я немного покопался, переключая On и Off туда и обратно и превращая as u32 в вызов .into(). И кажется, что as u32 полностью игнорирует любые реализации Into и просто конвертирует биты. В каком-то смысле это имело смысл, но как это работает, например, для u32 as f64?? Вы не можете просто преобразовать биты там. Что именно он делает?
Глядя на предложенный вопрос , кажется, что мой Enum вместо этого использует реализацию TryFrom (это тоже реализовано). Но для меня это не имеет смысла: зачем Rust использовать реализацию TryFrom, которая может вызвать панику из-за конкретно реализованной Into? Но даже это объяснение не имеет смысла, поскольку реализация TryFrom специально сопоставляет 0 с Bit::Off, 1 с Bit::On и все остальные значения с ошибками.
Обычно я просматриваю документацию по этому вопросу, но я не знаю, где конкретно найти документацию по этому вопросу, поскольку это скорее языковая функция, а не реализация чего-либо, указатель на это также помогает!
Ссылка на игровую площадку: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c06998e915b2b4aa44d58ec67d21eabb
Для справки, вот где я использовал 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)),
}
}
}
};
}
Придирка: вам следует impl From<Bit> for $t вместо impl Into<$t> for Bit. Также кажется, что struct Bit(bool) сделает вашу жизнь намного проще. Преобразование в/из bool тогда является простым и в любом случае будет предпочтительнее, чем возиться с числами.

Enum::Variant as NumberType извлекает дискриминант варианта.
as f32/f64 принимает целочисленный дискриминант и преобразует его в число с плавающей запятой.
as— это приведение типа , как и в других языках, например.(float) 123