为什么`From`不会被自动用于强制特征实现类型

Isa*_*kel 4 generics polymorphism implicit-conversion rust

我有两个特点:

trait Foo {}
trait Bar {}

struct FooImpl;
impl Foo for FooImpl {}

struct BarImpl;
impl Bar for BarImpl {}
Run Code Online (Sandbox Code Playgroud)

我要转换成第三种类型:

struct Baz;

trait IntoBaz {
    fn into(self) -> Baz;
}
Run Code Online (Sandbox Code Playgroud)

由于连贯性,我无法为两个特征定义两个impls IntoBaz,所以我换了一个:

struct FooWrapper<F>(F)
where
    F: Sized;

impl<F: Foo + Sized> From<F> for FooWrapper<F> {
    fn from(f: F) -> FooWrapper<F> {
        FooWrapper(f)
    }
}

impl<F: Foo + Sized> IntoBaz for FooWrapper<F> {
    fn into(self) -> Baz {
        Baz
    }
}
Run Code Online (Sandbox Code Playgroud)

我不包装另一个:

impl<B: Bar> IntoBaz for B {
    fn into(self) -> Baz {
        Baz
    }
}

fn do_thing<B: IntoBaz>(b: &B) {}

fn main() {
    do_thing(&BarImpl);
}
Run Code Online (Sandbox Code Playgroud)

到目前为止这么好,但为什么这条线不起作用?

fn main() {
    do_thing(&FooImpl);
}
Run Code Online (Sandbox Code Playgroud)

动机

我试图在没有引入重大变化的情况下向支持io::Write库添加支持fmt::Write.

最简单的方法是定义一些Write涵盖共享行为的内部特征,但是一致性问题意味着我不能只是将From<io::Write>实例写入内部特征.

我已经尝试包装io::Write实例,使强制显式化,因此编译器优先考虑较短路径并避免不连贯,但它不会自动强制使用From实例.

Pet*_*all 6

查看错误消息:

error[E0277]: the trait bound `FooImpl: Bar` is not satisfied
  --> src/main.rs:48:5
   |
48 |     do_thing(&FooImpl);
   |     ^^^^^^^^ the trait `Bar` is not implemented for `FooImpl`
   |
   = note: required because of the requirements on the impl of `IntoBaz` for `FooImpl`
note: required by `do_thing`
  --> src/main.rs:45:1
   |
45 | fn do_thing<B: IntoBaz>(b: &B) {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

它说FooImpl没有实现Bar,这是您全面IntoBaz for B实施的要求.

FooWrapper因为执行不相关的FooImpl是不一样的FooWrapper.在FromInto特点提供了一种类型之间的转换,但它不会自动发生.

您可以尝试为可以转换的内容添加实现FooWrapper,但这不起作用,因为实现可能重叠(并且专业化尚不稳定).

但您可以IntoBaz仅为FooImpl以下内容定义实现:

impl IntoBaz for FooImpl {
    fn into(self) -> Baz {
        IntoBaz::into(FooWrapper::from(self))
    }
}
Run Code Online (Sandbox Code Playgroud)

这将使您的代码编译:

fn main() {
    do_thing(&BarImpl);
    do_thing(&FooImpl);
}
Run Code Online (Sandbox Code Playgroud)