Rust 中 trait 的冲突实现

Posted

技术标签:

【中文标题】Rust 中 trait 的冲突实现【英文标题】:Conflicting implementations of trait in Rust 【发布时间】:2016-08-26 05:57:47 【问题描述】:

我想为&'a str 和最大为i32 的整数实现一个自定义特征,但Rust 不允许我这样做:

use std::convert::Into;

pub trait UiId 
    fn push(&self);


impl<'a> UiId for &'a str 
    fn push(&self) 


impl<T: Into<i32>> UiId for T 
    fn push(&self) 


fn main() 

编译失败,出现以下错误:

error[E0119]: conflicting implementations of trait `UiId` for type `&str`:
  --> src/main.rs:11:1
   |
7  | impl<'a> UiId for &'a str 
   | ------------------------- first implementation here
...
11 | impl<T: Into<i32>> UiId for T 
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&str`
   |
   = note: upstream crates may add new impl of trait `std::convert::From<&str>` for type `i32` in future versions

&amp;'a str 没有实现Into&lt;i32&gt;。是否可以为&amp;'a str 实现UiId 以及可以转换为i32 的所有内容而不指定具体类型?我该怎么做?

【问题讨论】:

我认为这一定是 Rust 确定实现是否重叠(或可能重叠)的限制,但我还没有找到任何地方说明规则的地方。 :-( 哦,对于正确的语言规范! 【参考方案1】:

&amp;'a str 没有实现Into&lt;i32&gt; 的事实不予考虑,因为不能保证以后不能添加。这会破坏你的代码。

因此,如果允许这样做,可能的破坏将使向库特征添加实现变得更加困难。

很遗憾,我在The Rust Programming Language Book 和Reference Manual 中都找不到相关文档。

我能找到的最好的是RFC 1023,它表示一个板条箱[...] 不能依赖Type: !Trait 持有,除非TypeTrait 是本地的。 p>

【讨论】:

我实际上不认为这是真的。这不就是孤儿规则的用途吗?您不能为外部类型添加外部特征 impls。在当前的 crate 中必须至少定义 trait 和 type 之一...为了让编译器对这样的情况进行推理,我认为 @LukasKalbertodt 查看我的编辑。它与 RFC 1023 中的 ophan 规则在同一个句子中。 哦,确实,这听起来很合理。谢谢!【参考方案2】:

我找到了使用标记特征的解决方法。无需夜间或实验功能。诀窍是我在我的 crate 中定义了标记特征并且不导出它,因此上游 crate 不可能在我实现它的类以外的类上定义标记。

标记特征下方是Numeric

我使用它是为了可以为任何可以转换为 f64 的东西实现 Into,也可以用于单独 impl 中的字符串以及其他类型。

Numeric trait 必须是 pub,因为他们警告说未来的版本将不允许在公共接口中使用私有 Trait。


use std::convert::Into;

pub trait Numeric 
impl Numeric for f64 
impl Numeric for f32 
impl Numeric for i64 
impl Numeric for i32 
impl Numeric for i16 
impl Numeric for i8 
impl Numeric for isize 
impl Numeric for u64 
impl Numeric for u32 
impl Numeric for u16 
impl Numeric for u8 
impl Numeric for usize 


pub trait UiId 
    fn push(&self);


impl<'a> UiId for &'a str 
    fn push(&self) 


impl<T: Into<i32> + Numeric> UiId for T 
    fn push(&self) 


【讨论】:

以上是关于Rust 中 trait 的冲突实现的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Rust Generic Struct/Trait 需要 Box<other trait>?

「Rust进阶笔记」Rust之derive特性总结

Rust Deref与自动解引用

rust trait 熟识系列:一日一trait之Seek trait

Rust语言圣经25 - 特征Trait

一天一门编程语言Rust 语言程序设计极简教程