有没有一种方法可以告诉编译器,没有人会为泛型类型的引用实现一个特性?

7
以下是演示问题的玩具代码:
trait Foo {}

trait Boo<T> {
    fn f() -> T;
}

impl<T> Boo<T> for i32
where
    T: Foo,
{
    fn f() -> T {
        unimplemented!();
    }
}

impl<'a, T> Boo<&'a T> for i32
where
    T: Foo,
{
    fn f() -> T {
        unimplemented!();
    }
}

我希望有两个通用的trait Boo实现,但是它无法编译:

error[E0119]: conflicting implementations of trait `Boo<&_>` for type `i32`:
  --> src/main.rs:16:1
   |
7  | / impl<T> Boo<T> for i32
8  | | where
9  | |     T: Foo,
10 | | {
...  |
13 | |     }
14 | | }
   | |_- first implementation here
15 | 
16 | / impl<'a, T> Boo<&'a T> for i32
17 | | where
18 | |     T: Foo,
19 | | {
...  |
22 | |     }
23 | | }
   | |_^ conflicting implementation for `i32`
   |
   = note: downstream crates may implement trait `Foo` for type `&_`

我不打算将此功能部分添加到其他的包中。我尝试过:

  • 将此代码移至二进制包,显然无法从其他包中使用
  • 将其移至私有mod
  • 将特征标记为pub(crate)

但这些尝试都没有成功。

是否有任何方法可以给编译器一个提示,让它不必关心任何人会为任何引用实现Foo

也许我的玩具示例不是最好的,所以这里是真正的代码。它用于与程序的C部分集成,所以有点复杂。

impl<T: MyTrait> MyFrom<Option<T>> for *mut c_void {
    fn my_from(x: Option<T>) -> Self {
        match x {
            Some(x) => <T>::alloc_heap_for(x),
            None => ptr::null_mut(),
        }
    }
}

impl<'a, T: MyTrait> MyFrom<Option<&'a T>> for *mut c_void {
    fn my_from(x: Option<&'a T>) -> Self {
        match x {
            Some(x) => x as *const T as *mut c_void,
            None => ptr::null_mut(),
        }
    }
}

6
这是一个关于 Rust 语言编译器问题的 GitHub Issue,编号为 #48869。 - Shepmaster
1个回答

1
这里的冲突与后一种实现的引用性无关。问题在于,在第一种实现中,T 可以是任何类型,包括引用类型。假设你进行以下函数调用:
let x: i32 = 10;
let result: &u8 = x.f();

在这一点上,类型解析器需要确定正在调用的函数。它找到了一个冲突的实现:
impl Boo<&u8> for i32 via Boo<T>  (T == &u8),
impl Boo<&u8> for i32 via Boo<&T> (T == u8),

如果您在后面的实现中使用了具体类型,那么您将遇到完全相同的问题:
// This will fail to compile
impl<T> Boo<T> for i32 { ... }
impl Boo<String> for i32 { ... }

这个冲突意味着编译器不能允许这两个实现共存。
你在这里要做的具体事情被称为“特化”; 它是指一套规则提案,该提案表示允许存在诸如此类的重叠实现,如果其中一个实现比另一个明显更“特定”,在这种情况下,编译器将选择更具体的实现。 这被跟踪为 RFC#1210

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接