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

问题描述 投票:1回答:2
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是在我的箱子里定义的。这实际上是由连贯/孤儿impls规则允许的吗?如果是这样,为实施Rand的事情实施AllValues的正确方法是什么?

rust traits
2个回答
2
投票

我应该能够为Rand实施AllValues,因为AllValues是在我的箱子里定义的。

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

要记住两个注意事项:

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

对于实现Rand的东西,实施AllValues的正确方法是什么?

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

也可以看看:


1
投票

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

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

(重点补充。)

由于我试图实现一个特征,我必须把它读作“你要实现它的特征或特征”。 This discussion about an eventually implemented rfc特别提到了一个类似于我提出的案例:impl<T: Copy> Clone for T是不允许的。

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

© www.soinside.com 2019 - 2024. All rights reserved.