请原谅这里的大量代码,但最小的示例很难解释,我已经try 使其尽可能简短.我试图用泛型界限在泛型类型上实现泛型特征,这会导致编译器错误:
note: downstream crates may implement trait `Named<_>` for type `ExampleThing`
奇怪的是,如果命名的函数不接受泛型参数,则可以很好地工作,所以我不明白为什么这会导致问题,以及如何修复它.
Minimally Broken Example个
代码的解释可能是阅读注释最容易的.在现实世界中,Named
是被引入到Talk<K>
和make_talk<T, K>
的现有代码库中的特征.
use std::fmt::Debug;
/// This trait is to be implemented by downstream crates for objects that talk
/// In order to break things there is a spurious extra piece of information of
/// generic type K that is to be included in the message
pub trait Talks<K> {
fn say(&self, extra: K);
}
/// A normal use case
pub struct ExampleThing(u64);
/// So we implement it manually like this
impl<K> Talks<K> for ExampleThing where K: Debug {
fn say(&self, extra: K) {
println!("I have the number {} [extra: {:?}]", self.0, extra);
}
}
/// Then this can make any that implemnets Talk, talk. We can always pass some
/// extra bit of info of type K to include in the message
pub fn make_talk<T, K>(thing: T, extra: K) where T: Talks<K> {
thing.say(extra);
}
/// A large collection of objects are named, exposing a name method,
/// and they are capable of including the extra info
pub trait Named<K> {
fn name(&self, extra: K) -> String;
}
/// For example this guy
pub struct Person{ name: String }
impl<K> Named<K> for Person where K: Debug {
fn name(&self, extra: K) -> String {
format!("{:?} of {:?}" , self.name.clone(), extra)
}
}
/// And then we can try make it so that all things that implement Name
/// introduce themselves automatically using Name
impl<K, T> Talks<K> for T where
K: Debug,
T: Named<K>
{
fn say(&self, extra: K) {
println!("My name is {}", self.name(extra))
}
}
fn main() {
let example = ExampleThing(42);
make_talk(example, "Did it work?");
let person = Person{name: "Bob".to_string()};
make_talk(person, 1234);
}
产生此错误:
error[E0119]: conflicting implementations of trait `Talks<_>` for type `ExampleThing`
--> src/main.rs:43:1
|
14 | impl<K> Talks<K> for ExampleThing where K: Debug {
| ------------------------------------------------ first implementation here
...
43 | / impl<K, T> Talks<K> for T where
44 | | K: Debug,
45 | | T: Named<K>
| |___________^ conflicting implementation for `ExampleThing`
|
= note: downstream crates may implement trait `Named<_>` for type `ExampleThing`
Tiny change that works个
如果我们go 掉通用边界Named<K>
并将其替换为Named<u64>
,那么一切都很好:
impl<K, T> Talks<K> for T where
K: Debug,
T: Named<u64>
{
fn say(&self, extra: K) {
println!("My name is {}", self.name(999))
}
}
这会产生以下结果:
I have the number 42 [extra: "Did it work?"]
My name is "Bob" of 999
Question个
这里发生什么事情?我如何解决这个问题,以便在一揽子实现中将类型为K
的extra
字段传递到Named<K>
中.关于下游 crate 的错误消息令人困惑,因为它仅在性状界限包括K时适用.