如何使用 blanket Into trait 实现转换回原始类型?
How do I use the blanket Into trait implementation to convert back to the original type?
From
特征的文档对特征本身和任何可能的失败有以下说明:
One should always prefer implementing From
over Into
because implementing From
automatically provides one with an implementation of Into
thanks to the blanket implementation in the standard library.
和
Note: This trait must not fail. If the conversion can fail, use TryFrom
.
我有以下 From
将整数转换为罗马数字的实现:
/// ### UpperRoman
/// Upper-case Roman numerals. The `None` variant is for handling invalid conversions.
pub enum UpperRoman {
M,
CM,
D,
CD,
C,
XC,
L,
XL,
X,
IX,
V,
IV,
I,
None,
}
impl From<u32> for UpperRoman {
/// ### from
/// Converts a `u32` to an `UpperRoman` numeral variant.
fn from(numeral: u32) -> Self {
match numeral {
1000 => Self::M,
900 => Self::CM,
500 => Self::D,
400 => Self::CD,
100 => Self::C,
90 => Self::XC,
50 => Self::L,
40 => Self::XL,
10 => Self::X,
9 => Self::IX,
5 => Self::V,
4 => Self::IV,
1 => Self::I,
_ => Self::None,
}
}
}
只有少数有效案例。对于任何无效输入,我都定义了一个变体 UpperRoman::None
,这意味着没有匹配给定输入的罗马数字。这会处理任何失败情况,因此满足文档中设置的要求。
如果我想使用自动生成的 Into
-trait 实现将罗马数字转换回整数怎么办? UpperRoman::into
函数如何处理 UpperRoman::None
的情况?我唯一的选择是匹配 UpperRoman::into
的可能输入以确保在调用函数之前它不是 UpperRoman::None
变体吗?
这里有点混乱。考虑到 From<u32> for UpperRoman
的实现,编译器 不会自动 给你 相反的转换 (即从 UpperRoman
到 u32
).相反,它会给你双重实现:Into<UpperRoman> for u32
,它在语义上具有相同的方向。 Into
的全面实施将允许程序员编写以下任一内容:
let c = UpperRoman::from(100);
let c: UpperRoman = 100.into();
话虽如此,这意味着您需要按照自己的方式进行有意义的相反转换。在这种情况下,最好假设从 u32
到 UpperRoman
的转换是一个容易出错的转换,因为并非所有整数都映射到单个罗马数字。
这也将允许您删除 None
变体,它仅用作非常不需要的“空”值,并且可以通过 Option
添加到任何类型。
use std::convert::TryFrom;
pub enum UpperRoman {
M,
CM,
D,
CD,
C,
XC,
L,
XL,
X,
IX,
V,
IV,
I,
}
impl TryFrom<u32> for UpperRoman {
type Error = &'static str;
fn try_from(numeral: u32) -> Result<Self, Self::Error> {
match numeral {
1000 => Ok(Self::M),
900 => Ok(Self::CM),
// expand the rest here
4 => Ok(Self::IV),
1 => Ok(Self::I),
_ => Err("that is no good!"),
}
}
}
(为此转换创建更好的错误类型留作 reader 的练习。)
完成后,将 UpperRoman
转换为 u32
就很简单了:
impl From<UpperRoman> for u32 {
fn from(v: UpperRoman) -> Self {
Self::M => 1000,
// ... expand the remaining variants exhaustively here, no None
}
}
另请参阅:
From
特征的文档对特征本身和任何可能的失败有以下说明:
One should always prefer implementing
From
overInto
because implementingFrom
automatically provides one with an implementation ofInto
thanks to the blanket implementation in the standard library.
和
Note: This trait must not fail. If the conversion can fail, use
TryFrom
.
我有以下 From
将整数转换为罗马数字的实现:
/// ### UpperRoman
/// Upper-case Roman numerals. The `None` variant is for handling invalid conversions.
pub enum UpperRoman {
M,
CM,
D,
CD,
C,
XC,
L,
XL,
X,
IX,
V,
IV,
I,
None,
}
impl From<u32> for UpperRoman {
/// ### from
/// Converts a `u32` to an `UpperRoman` numeral variant.
fn from(numeral: u32) -> Self {
match numeral {
1000 => Self::M,
900 => Self::CM,
500 => Self::D,
400 => Self::CD,
100 => Self::C,
90 => Self::XC,
50 => Self::L,
40 => Self::XL,
10 => Self::X,
9 => Self::IX,
5 => Self::V,
4 => Self::IV,
1 => Self::I,
_ => Self::None,
}
}
}
只有少数有效案例。对于任何无效输入,我都定义了一个变体 UpperRoman::None
,这意味着没有匹配给定输入的罗马数字。这会处理任何失败情况,因此满足文档中设置的要求。
如果我想使用自动生成的 Into
-trait 实现将罗马数字转换回整数怎么办? UpperRoman::into
函数如何处理 UpperRoman::None
的情况?我唯一的选择是匹配 UpperRoman::into
的可能输入以确保在调用函数之前它不是 UpperRoman::None
变体吗?
这里有点混乱。考虑到 From<u32> for UpperRoman
的实现,编译器 不会自动 给你 相反的转换 (即从 UpperRoman
到 u32
).相反,它会给你双重实现:Into<UpperRoman> for u32
,它在语义上具有相同的方向。 Into
的全面实施将允许程序员编写以下任一内容:
let c = UpperRoman::from(100);
let c: UpperRoman = 100.into();
话虽如此,这意味着您需要按照自己的方式进行有意义的相反转换。在这种情况下,最好假设从 u32
到 UpperRoman
的转换是一个容易出错的转换,因为并非所有整数都映射到单个罗马数字。
这也将允许您删除 None
变体,它仅用作非常不需要的“空”值,并且可以通过 Option
添加到任何类型。
use std::convert::TryFrom;
pub enum UpperRoman {
M,
CM,
D,
CD,
C,
XC,
L,
XL,
X,
IX,
V,
IV,
I,
}
impl TryFrom<u32> for UpperRoman {
type Error = &'static str;
fn try_from(numeral: u32) -> Result<Self, Self::Error> {
match numeral {
1000 => Ok(Self::M),
900 => Ok(Self::CM),
// expand the rest here
4 => Ok(Self::IV),
1 => Ok(Self::I),
_ => Err("that is no good!"),
}
}
}
(为此转换创建更好的错误类型留作 reader 的练习。)
完成后,将 UpperRoman
转换为 u32
就很简单了:
impl From<UpperRoman> for u32 {
fn from(v: UpperRoman) -> Self {
Self::M => 1000,
// ... expand the remaining variants exhaustively here, no None
}
}
另请参阅: