我有两个特点:
trait Foo {}
trait Bar {}
struct FooImpl;
impl Foo for FooImpl {}
struct BarImpl;
impl Bar for BarImpl {}
我希望你能将第三种类型转换成:
struct Baz;
trait IntoBaz {
fn into(self) -> Baz;
}
由于一致性,我无法为这两个特质定义两个IntoBaz
的impl
,因此我将其中一个进行包装:
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);
}
动机
我正在尝试为一个支持fmt::Write
的库添加io::Write
支持,而不引入破坏性更改。
最简单的方式是定义一些内部的Write
特征来涵盖共享的行为,但一致性问题意味着我不能仅仅写入From<io::Write>
实例到内部特征中。
我已经尝试了包装io::Write
实例,使得强制转换明确,以便编译器优先选择更短的路径并避免不一致性,但它不会使用From
实例进行自动强制转换。
FooImpl
没有实现Bar
接口(而这是你的IntoBaz
实现所必需的)。难道你的本意不是进行如下操作吗:do_thing(&FooWrapper(FooImpl));
? - Peter Hallfrom()
orinto()
don't just get automagically called. You would need to do something like:do_thing(&FooWrapper::from(FooImpl));
- Peter HallDeref
,这将导致包装器自动衰减为包装的类型。 您可以在 Nomicon 中查看所有强制转换的完整列表:https://doc.rust-lang.org/nomicon/coercions.html。 - Sven Marnachfrom()
有时会被语言自动调用 - 我希望避免在调用现场手动使用包装器。对我来说,似乎应该有一种方法可以使用From
或类似的东西来解决这个协同问题。 - Isaac van Bakelfrom()
有时会被语言自动调用” — 它可能看起来可以与某些库一起使用,但这只是那些库需要参数为Into<T>
并显式调用.into()
,就像do_thing
的主体一样。 - Peter Hall