为两步 From 创建通用 From/Into 快捷方式
Making a generic From/Into shortcut for two-steps From
StructA
实现了 From<StructB>
,StructB
实现了 From<S>
.
我如何通用地实现 'shortcut' Into<StructA> for S
或 From<S> for StructA
?
如果这是个坏主意,请告诉我。但是为了学习,请解释一下如何做。
这是我的尝试:
struct StructA {
f: StructB
}
struct StructB {
g: i32
}
impl From<StructB> for StructA {
fn from(v: StructB) -> Self {
Self {
f: v
}
}
}
impl From<i32> for StructB {
fn from(v: i32) -> Self {
Self {
g: v
}
}
}
impl<T: Into<StructA>, S: Into<T>> Into<StructA> for S {
fn into(self) -> StructA {
let i: T = self.into();
i.into()
}
}
我得到的错误是 the type parameter 'T' is not constrained by the impl trait, self type, or predicates
。
我不明白。 T
不是受Into<StructA>
约束吗?
错误消息基本上表明编译器无法推断 T
可能是什么类型——它基本上必须弄清楚是否存在任何类型 T
使得给定的特征边界 T: Into<StructA>, S: Into<T>
得到满足,这在 Rust 中是不可能的。一个问题是,如评论中所述,可能有多种类型 T
满足特征界限,在这种情况下,编译器无法确定使用哪一种。
此外,Into
特征已经在标准库中全面实施。
impl<T, U: From<T>> Into<U> for T;
编译器无法保证此 impl 不会与您的一揽子 impl 重叠,这也会使实现不明确。
我建议您直接明确实施 From<i32> for StructA
。如果您需要许多这样的实现,宏可能会有用。
没有办法生成完全通用的解决方案,因为即使您解决了“不受约束的类型参数”错误,您也会 运行 陷入“特征实现冲突”错误。这是我所能得到的最接近的,它允许将 StructB
转换为 StructA
或 将任何可以转换为 StructB
的类型转换为 StructA
:
#[derive(Eq, PartialEq, Debug)]
struct StructA {
f: StructB
}
#[derive(Eq, PartialEq, Debug)]
struct StructB {
g: i32
}
impl From<i32> for StructB {
fn from(v: i32) -> Self {
Self {
g: v
}
}
}
impl<T> From<T> for StructA
where
T: Into<StructB>
{
fn from(t: T) -> StructA {
let structb = t.into();
StructA {
f: structb
}
}
}
fn main() {
let a1: StructA = StructB { g: 12 }.into();
let a2: StructA = 12.into();
assert_eq!(a1, a2);
}
据我所知,这在稳定的 Rust 上是不可能的,因为它需要某种形式的专业化。让我们考虑一下这段代码:
// "StructB -> StructA"
impl From<StructB> for StructA {
fn from(v: StructB) -> Self {
Self { f: v }
}
}
impl From<i32> for StructB {
fn from(v: i32) -> Self {
Self { g: v }
}
}
// "shortcut"
impl<T> From<T> for StructA
where
StructB: From<T>,
{
fn from(t: T) -> Self {
Self::from(StructB::from(t))
}
}
编译器会抱怨 "StructB -> StructA"
impl 与 "shortcut"
impl 冲突。这是真的,因为 From<T>
本身有一个 blanket implementation。
现在使用 Into
根本没有帮助,因为 Into
是自反的。因此,即使您克服了“不受约束”的错误,您也会回到相互冲突的实现中。
不过!
每晚都有可能。通过使用 auto traits (here's a nice article about it) 的小技巧,我们可以将“快捷方式”实现限制为仅涵盖不同于 StructB
.
的类型
StructA
实现了 From<StructB>
,StructB
实现了 From<S>
.
我如何通用地实现 'shortcut' Into<StructA> for S
或 From<S> for StructA
?
如果这是个坏主意,请告诉我。但是为了学习,请解释一下如何做。
这是我的尝试:
struct StructA {
f: StructB
}
struct StructB {
g: i32
}
impl From<StructB> for StructA {
fn from(v: StructB) -> Self {
Self {
f: v
}
}
}
impl From<i32> for StructB {
fn from(v: i32) -> Self {
Self {
g: v
}
}
}
impl<T: Into<StructA>, S: Into<T>> Into<StructA> for S {
fn into(self) -> StructA {
let i: T = self.into();
i.into()
}
}
我得到的错误是 the type parameter 'T' is not constrained by the impl trait, self type, or predicates
。
我不明白。 T
不是受Into<StructA>
约束吗?
错误消息基本上表明编译器无法推断 T
可能是什么类型——它基本上必须弄清楚是否存在任何类型 T
使得给定的特征边界 T: Into<StructA>, S: Into<T>
得到满足,这在 Rust 中是不可能的。一个问题是,如评论中所述,可能有多种类型 T
满足特征界限,在这种情况下,编译器无法确定使用哪一种。
此外,Into
特征已经在标准库中全面实施。
impl<T, U: From<T>> Into<U> for T;
编译器无法保证此 impl 不会与您的一揽子 impl 重叠,这也会使实现不明确。
我建议您直接明确实施 From<i32> for StructA
。如果您需要许多这样的实现,宏可能会有用。
没有办法生成完全通用的解决方案,因为即使您解决了“不受约束的类型参数”错误,您也会 运行 陷入“特征实现冲突”错误。这是我所能得到的最接近的,它允许将 StructB
转换为 StructA
或 将任何可以转换为 StructB
的类型转换为 StructA
:
#[derive(Eq, PartialEq, Debug)]
struct StructA {
f: StructB
}
#[derive(Eq, PartialEq, Debug)]
struct StructB {
g: i32
}
impl From<i32> for StructB {
fn from(v: i32) -> Self {
Self {
g: v
}
}
}
impl<T> From<T> for StructA
where
T: Into<StructB>
{
fn from(t: T) -> StructA {
let structb = t.into();
StructA {
f: structb
}
}
}
fn main() {
let a1: StructA = StructB { g: 12 }.into();
let a2: StructA = 12.into();
assert_eq!(a1, a2);
}
据我所知,这在稳定的 Rust 上是不可能的,因为它需要某种形式的专业化。让我们考虑一下这段代码:
// "StructB -> StructA"
impl From<StructB> for StructA {
fn from(v: StructB) -> Self {
Self { f: v }
}
}
impl From<i32> for StructB {
fn from(v: i32) -> Self {
Self { g: v }
}
}
// "shortcut"
impl<T> From<T> for StructA
where
StructB: From<T>,
{
fn from(t: T) -> Self {
Self::from(StructB::from(t))
}
}
编译器会抱怨 "StructB -> StructA"
impl 与 "shortcut"
impl 冲突。这是真的,因为 From<T>
本身有一个 blanket implementation。
现在使用 Into
根本没有帮助,因为 Into
是自反的。因此,即使您克服了“不受约束”的错误,您也会回到相互冲突的实现中。
不过!
每晚都有可能。通过使用 auto traits (here's a nice article about it) 的小技巧,我们可以将“快捷方式”实现限制为仅涵盖不同于 StructB
.