编译器强迫我执行特征方法,但我的类型永远无法满足方法上绑定的“自定义”特征

时间:2019-04-04 17:18:35

标签: rust traits

我有一个特征Foo。我想强迫实现者定义一个方法,如果这些实现者实现了另一个特征(在本示例中为Clone),则该实现者将对其进行定义。我的想法(Playground):

trait Foo {
    // Note: in my real application, the trait has other methods as well,
    // so I can't simply add `Clone` as super trait
    fn foo(&self) 
    where 
        Self: Clone;
}

struct NoClone;
impl Foo for NoClone {}

可悲的是,这导致:

error[E0046]: not all trait items implemented, missing: `foo`
 --> src/lib.rs:8:1
  |
2 | /     fn foo(&self) 
3 | |     where 
4 | |         Self: Clone;
  | |____________________- `foo` from trait
...
8 |   impl Foo for NoClone {}
  |   ^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation

我不理解此错误:编译器清楚地知道NoClone没有实现Clone,所以为什么我需要为foo提供定义?特别是,如果我尝试提供定义(Playground):

impl Foo for NoClone {
    fn foo(&self) 
    where 
        Self: Clone
    {
        unreachable!()
    }
}

我得到了错误:

error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied
  --> src/lib.rs:9:5
   |
9  | /     fn foo(&self) 
10 | |     where 
11 | |         Self: Clone
12 | |     {
13 | |         unreachable!()
14 | |     }
   | |_____^ the trait `std::clone::Clone` is not implemented for `NoClone`
   |
   = help: see issue #48214
   = help: add #![feature(trivial_bounds)] to the crate attributes to enable

因此,编译器肯定知道。 (仅供参考:使用#![feature(trivial_bounds)]可以编译,但是我不想用unreachable!()作为主体来定义一堆方法。)

为什么编译器会强迫我提供方法定义?我可以以某种方式解决此问题吗?

1 个答案:

答案 0 :(得分:12)

特征的所有实现者都需要实现所有没有默认实现的方法。具有定义的接口是特征的关键。向方法添加特征边界不会改变此规则。

这是language reference关于主题的内容:

  

特征实现必须定义由实现的特征声明的所有非默认关联项,可以重新定义由实现的特征定义的默认关联项,并且不能定义任何其他项。

这也意味着在特质的方法声明中绑定到Self上的特质在功能上等同于声明超特质,除了特质只能在声明绑定的方法中使用。

显而易见的解决方法是为在Self上有其他要求的方法定义单独的特征:

trait FooExt: Foo + Clone {
    fn foo(&self);
}

您现在可以为所有类型实现Foo,还可以为FooExt类型实现Clone

已按照注释中的要求进行了更新:这里有一个GitHub issue discussing whether it should be allowed to implement methods with unsatisfiable trait bounds without the method body,因此至少可以删除{ unimplemted()! }部分。截至2019年4月,这一讨论尚未得出任何结论,甚至还没有解决实现不可调用方法的确切语法。