StructA
实现From<StructB>
,StructB
实现From<S>
。
如何通用地实现"快捷方式"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>
本身有一个一揽子实现。
现在使用Into
根本没有帮助,因为Into
是自反的。所以即使你克服了";不受约束";错误,您将返回到冲突的实现。
然而夜间有可能。通过使用自动特征的一点技巧(这里有一篇关于它的好文章),我们可以限制";快捷方式";实现仅覆盖不同于CCD_ 25的类型。
游乐场连接