我有个特质Foo。如果那些实现者实现了另一个特征(Clone在本示例中),我想强迫实现者定义一个方法。我的想法(游乐场):
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 {}
Run Code Online (Sandbox Code Playgroud)
可悲的是,这导致:
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
Run Code Online (Sandbox Code Playgroud)
我不理解此错误:编译器清楚地知道该错误NoClone不会实现Clone,那么为什么需要为它提供定义foo?特别是,如果我尝试提供一个定义(Playground):
impl Foo for NoClone {
fn foo(&self)
where
Self: Clone
{
unreachable!()
}
}
Run Code Online (Sandbox Code Playgroud)
我收到错误:
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
Run Code Online (Sandbox Code Playgroud)
因此,编译器肯定知道。(仅供参考:#![feature(trivial_bounds)]它可以编译,但是我不想用unreachable!()as主体定义一堆方法。)
为什么编译器强迫我提供方法定义?我可以以某种方式解决此问题吗?
Sve*_*ach 12
All implementors of a trait need to implement all methods that don't have a default implementation. It's the point of a trait that it has a defined interface. Adding trait bounds to a method does not change anything about this rule.
This is what the language reference says on the topic:
A trait implementation must define all non-default associated items declared by the implemented trait, may redefine default associated items defined by the implemented trait, and cannot define any other items.
This also means that a trait bound on Self in a method declaration on a trait is functionally equivalent to declaring a supertrait, except that the trait can only be used in the method that declares the bound.
The obvious work-around is to define a separate trait for the methods that have additional requirements on Self:
trait FooExt: Foo + Clone {
fn foo(&self);
}
Run Code Online (Sandbox Code Playgroud)
You can now implement Foo for all types, and FooExt in addition for the types that are Clone.
Updated as requested in the comments: There is a GitHub issue discussing whether it should be allowed to implement methods with unsatisfiable trait bounds without the method body, so at least the { unimplemted()! } part could be dropped. As of April 2019, this discussion has not come to any conclusion yet, and not even the exact syntax for implementing the uncallable methods has been settled.
| 归档时间: |
|
| 查看次数: |
211 次 |
| 最近记录: |