【问题标题】:Compiler forces me to implement trait method but the `Self` trait bound on method is never satisfied for my type编译器强制我实现 trait 方法,但我的类型永远不会满足方法上的 `Self` trait 绑定
【发布时间】:2019-08-26 13:08:40
【问题描述】:

我有一个特质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!() 为主体的方法。)

为什么编译器强制我提供方法定义?我能以某种方式解决这个问题吗?

【问题讨论】:

  • 我认为这种功能会破坏V-table
  • @Stargateur 或者只是另一个特征不安全的条件。
  • 你可能会觉得this issue很有趣。

标签: rust traits


【解决方案1】:

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

这是language reference 在这个话题上所说的:

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

这也意味着,在 trait 的方法声明中绑定在 Self 上的 trait 在功能上等同于声明超特征,只是该 trait 只能在声明边界的方法中使用。

显而易见的解决方法是为对Self 有额外要求的方法定义一个单独的特征:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 2019-12-23
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多