首页 > 解决方案 > 为什么`From`不自动用于强制特征实现类型

问题描述

我有两个特点:

trait Foo {}
trait Bar {}

struct FooImpl;
impl Foo for FooImpl {}

struct BarImpl;
impl Bar for BarImpl {}

我想转换成的第三种类型:

struct Baz;

trait IntoBaz {
    fn into(self) -> Baz;
}

由于连贯性,我无法为这两个特征定义两个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
    }
}

我不包装另一个:

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

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

fn main() {
    do_thing(&BarImpl);
}

到目前为止一切顺利,但为什么这条线不起作用?

fn main() {
    do_thing(&FooImpl);
}

动机

我正在尝试在不引入重大更改的情况下向io::Write具有支持的库添加支持。fmt::Write

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

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

标签: genericsrustpolymorphismimplicit-conversion

解决方案


查看错误信息:

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) {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

这就是说FooImpl没有实现Bar,这是您的全面IntoBaz for B实现的要求。

FooWrapper实现不相关,因为FooImplFooWrapper. From和特征提供了一种在类型之间进行转换的Into方法,但它不会自动发生。

您可能会尝试为可以转换为 的事物添加实现FooWrapper,但这不起作用,因为实现可能重叠(并且专业化还不稳定)。

但是您可以IntoBaz为 just 定义一个实现FooImpl

impl IntoBaz for FooImpl {
    fn into(self) -> Baz {
        IntoBaz::into(FooWrapper::from(self))
    }
}

这将使您的代码编译:

fn main() {
    do_thing(&BarImpl);
    do_thing(&FooImpl);
}

推荐阅读