容器类型的“From”实现,用于转换所包含的类型

V0l*_*dek 10 generics rust

我有一个容器类型C<T>,其中包含类型的对象T

struct C<T> {
    insides: T
}
Run Code Online (Sandbox Code Playgroud)

假设我有两种类型AB可以使用From特征进行转换:

struct A { }

struct B { }

impl From<A> for B {
    fn from(a: A) -> B {
        B { }
    }
}
Run Code Online (Sandbox Code Playgroud)

就我而言,很自然地,我应该能够使用此转换轻松地将其放置在需要的C<A>地方C<B>From这可以通过扩展到容器类型来完成:

impl From<C<A>> for C<B> {
    fn from(ca: C<A>) -> C<B> {
        C { insides: B::from(ca.insides) }
    }
}


fn foo(cb: C<B>) {}

fn main() {
    let ca = C { insides: A {} };
    foo(ca.into());
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,一切都按预期编译和工作。

但这是一种相当自然的模式,适用于任何一对可转换类型,而不仅仅是AB。因此,人们可能需要一个全面的特征实现:

impl<T, U> From<C<T>> for C<U> where U: From<T> {
    fn from(t: C<T>) -> C<U> {
        C { insides: U::from(t.insides) }
    }
}
Run Code Online (Sandbox Code Playgroud)

这不起作用:

error[E0119]: conflicting implementations of trait `std::convert::From<C<_>>` for type `C<_>`
  --> src/main.rs:19:1
   |
19 | impl<T, U> From<C<T>> for C<U> where U: From<T> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T> From<T> for T;

For more information about this error, try `rustc --explain E0119`.
Run Code Online (Sandbox Code Playgroud)

我理解这个错误:对于任何X如果我们指定 impl forT=X,U=X我们会发生冲突,因为X: From<X>对于所有X. 但这是一个相当烦人的边缘情况。有办法解决这个问题吗?以某种方式指定一个绑定说法T != U,或者任何其他方式告诉 Rust 使用corefor中的任何总括实现T=U以及我的 impl 其余部分?

Cha*_*man 2

在每晚,您可以使用自动特征来做到这一点:

#![feature(auto_traits, negative_impls)]

auto trait NotSame {}

impl<T> !NotSame for (T, T) {}

struct C<T> {
    insides: T,
}

impl<T, U> From<C<T>> for C<U>
where
    U: From<T>,
    (T, U): NotSame,
{
    fn from(t: C<T>) -> C<U> {
        C {
            insides: U::from(t.insides),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

但请注意,它可能具有相同的专业化健全性漏洞(当与生命周期交互时) - 我对此不确定。

但请注意,这实际上是(ab)使用编译器错误 - 编译器不会分析和证明 impl 不重叠,而是这些功能没有完全实现,因此编译器不会检查一致性。这意味着您需要更多类型注释,也意味着您不能使用impl<T> From<C<T>> for C<T> {}in std,因为它与您的类型注释重叠:

#![feature(auto_traits, negative_impls)]

auto trait NotSame {}

// Need at least one negative impl
impl !NotSame for (i32, String) {}

#[derive(Debug)]
struct C<T> {
    insides: T,
}

impl<T, U> From<C<T>> for C<U>
where
    U: From<T>,
    (T, U): NotSame,
{
    fn from(t: C<T>) -> C<U> {
        C {
            insides: U::from(t.insides),
        }
    }
}

#[derive(Debug)]
struct A;
#[derive(Debug)]
struct B;
impl From<A> for B {
    fn from(_: A) -> B { B }
}

fn main() {
    let c: C<B> = C { insides: B };
    dbg!(<C<B> as From<C<B>>>::from(c));
}
Run Code Online (Sandbox Code Playgroud)

操场

不要在生产中使用它,特别是因为它可能随时被修复。