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]
}
}
}
The preceding code produces the following compile-time error:
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 {
| ^
According to the restrictions on implementing traits mentioned here I should be able to implement Rand
for AllValues
since AllValues
is defined in my crate. Is this actually allowed by the coherence/orphan impl
s rules? And if so, what is the right way to implement Rand
for things that implement AllValues
?
No, you are only allowed to implement your own trait
AllValues
for types you didn't define. You can't make the logical jump to implementing an unrelated trait that you also didn't define.There are two considerations to remember:
Rand
!Rand
forT
some time in the future.I don't believe there is one. I'd just introduce a wrapper type that holds a value or a reference to a value that implements your trait and implement
Rand
for that.See also:
I see now where my mistake in interpretation was. Quoting from the the traits section of the book:
(Emphasis added.)
Since I was trying to implement a trait I must have read that as "either the trait or the trait you’re implementing it for". This discussion about an eventually implemented rfc specifically mentions a similar case to the one I presented :
impl<T: Copy> Clone for T
as something that would not be allowed.Creating a wrapper type as suggested elsewhere is one solution for this problem. Assuming the ownership of the type implementations allows it, implementing the trait explicitly for each concrete instance, (optionally condensing the code with a macro,) as suggested here is another.