为引用和非引用类型实现 trait 会导致实现冲突 [英] Implementing a trait for reference and non reference types causes conflicting implementations

查看:37
本文介绍了为引用和非引用类型实现 trait 会导致实现冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个特征并为所有非引用类型提供一个实现,并为所有引用类型提供另一个实现.

I'm trying to create a trait and provide one implementation for all non-reference types, and another for all reference types.

编译失败:

trait Foo {}
impl<T> Foo for T {}
impl<'a, T> Foo for &'a mut T {}

由于错误而失败

error[E0119]: conflicting implementations of trait `Foo` for type `&mut _`:
 --> src/main.rs:3:1
  |
2 | impl<T> Foo for T {}
  | -------------------- first implementation here
3 | impl<'a, T> Foo for &'a mut T {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&mut _`

奇怪的是,这是有效的:

Strangely enough, this works:

trait Bar {}

impl<T> Bar for T
where
    T: Clone,
{}

impl<'a, T> Bar for &'a mut T
where
    T: Clone + 'static,
{}

为什么带有 Clone 约束的版本可以工作,没有它我如何让它工作?

Why does the version with the Clone constraint work, and how can I make it work without it?

推荐答案

如您所知,通用 T 可以是任何东西¹,因此 Foo 实现重叠(冲突) 每当第一个 impl 中的 T&'a mut U,因为第二个 impl 也涵盖了这种情况(当 T>U).

As you have learned, a generic T can be anything¹, so the Foo impls overlap (conflict) whenever T in the first impl is &'a mut U, because the second impl also covers that case (when T is U).

Clone 版本的工作原理很简单,因为 &mut 引用从不实现 Clone,所以 T 和 T 之间没有重叠:Clone&'a mut T.² 如果您尝试为不可变 (&) 引用实现 Bar,您会再次发生冲突,因为不可变引用do实现了Clone.

The Clone version works simply because &mut references never implement Clone, so there's no overlap between T where T: Clone and &'a mut T.² If you try to implement Bar for immutable (&) references, you will have a conflict again, because immutable references do implement Clone.

[H]没有它我怎么能让它工作?

[H]ow can I make it work without it?

如果它"是指引用类型的一种实现,另一种是非引用类型的不同实现,那么这在 Rust 中是不可能的,原因与您无法以一种方式为 struct<实现 trait/code>s 和 enums 的另一种方式:根本没有办法表达它(在当前的 Rust 中).

If by "it" you mean one implementation for reference types and another, different one for non-reference types, that's not possible in Rust for the same reason you can't implement a trait one way for structs and another way for enums: there simply is no way to express it (in current Rust).

一种可能适用于您的常见模式是为您需要的任何非引用类型单独实现您的特征,然后添加一个一揽子实现",涵盖对类型的任何引用trait 已经实现,例如:

One common pattern that might work for you is implementing your trait individually for whatever non-reference types you need, and then adding a "blanket impl" that covers any reference to a type for which the trait is already implemented, e.g.:

impl Foo for u32 { ... }
impl Foo for i32 { ... }
impl<'a, T> Foo for &'a T where T: Foo + 'a { ... }
impl<'a, T> Foo for &'a mut T where T: Foo + 'a { ... }

<小时>

¹ 好吧,至少是大小的任何东西.你必须添加 ?Sized 如果这不是你想要的想要.


¹ Well, anything that is Sized, at least. You have to add ?Sized if that's not what you want.

² where T: Clone + 'static 子句无关紧要,因为 &'a mut T 永远不会是 CloneT 本身是否存在.

² The where T: Clone + 'static clause doesn't matter, because &'a mut T will never be Clone whether T itself is or not.

这篇关于为引用和非引用类型实现 trait 会导致实现冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆