对于实现我拥有的特征的所有类型,都不能实现我不拥有的特征

时间:2017-05-15 21:25:59

标签: rust traits

pub trait AllValues {
    fn all_values() -> Vec<Self> where Self: std::marker::Sized;
}

use rand::Rand;
use rand::Rng;
impl<T: AllValues + Sized> Rand for T {
    fn rand<R: Rng, T>(rng: &mut R) -> T {
        let values = T::all_values();

        let len = values.len();

        if len == 0 {
            panic!("Cannot pick a random value because T::all_values() returned an empty vector!")
        } else {
            let i = rng.gen_range(0, len);

            values[i]
        }
    }
}

上面的代码产生以下编译时错误:

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`); only traits defined in the current crate can be implemented for a type parameter
   --> src/lib.rs:137:1
    |
137 | impl<T: AllValues + Sized> Rand for T {
    | ^

根据实施提到的特征here的限制,我应该能够为Rand实施AllValues,因为我的箱子中定义了AllValues。这实际上是由连贯/孤儿impl规则允许的吗?如果是这样,对于实施Rand的内容,实施AllValues的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

  

我应该能够为Rand实施AllValues,因为我的箱子中定义了AllValues

不,您只能为未定义的类型实现自己的特征AllValues。你不能进行逻辑跳转来实现你也没有定义的无关特征。

要记住两个注意事项:

  • 如果您的特征是公开的(它基于您提供的代码),那么您不是唯一可以实现特征的特征。你的箱子的消费者可能能够为他们自己的类型实现它,他们也可能决定实施Rand
  • rand crate可能决定在将来某个时间为Rand实施T
  

为实施Rand的内容实施AllValues的正确方法是什么?

我不相信有一个。我只是介绍一个包装器类型,它包含一个值或对一个实现你的特征的值的引用,并为此实现Rand

另见:

答案 1 :(得分:1)

我现在看到我的解释错误在哪里。引自the traits section of the book

  

实施特征还有一个限制:要么是特质   或者你实现它的类型必须由你定义。或者更多   确切地说,其中一个必须与impl在同一个箱子中定义   你正在写作。

(强调补充。)

因为我试图实现一个特性,所以我必须把它读作“要么是>要实现它的特性或特征”。 This discussion about an eventually implemented rfc特别提到了与我提出的案例相似的案例:impl<T: Copy> Clone for T是不允许的事情。

如其他地方所建议的那样创建包装器类型是解决此问题的一种方法。假设类型实现的所有权允许它,为每个具体实例显式地实现特征(可选地用宏来压缩代码),如建议的那样here是另一个。