Reputation: 257
I have the following simple setup:
pub trait Distribution {
type T;
fn sample(&self) -> Self::T;
}
pub fn foo<D, U>(dist: &D, f: &Fn(&[f64]))
where
D: Distribution<T = U>,
U: std::ops::Index<usize>,
{
let s = dist.sample();
f(&s[..]);
}
foo
accepts a generic container that implements Distribution
and a function, but if I use it in an example like this:
struct Normal {}
impl Distribution for Normal {
type T = Vec<f64>;
fn sample(&self) -> Self::T {
vec![0.0]
}
}
fn main() {
let x = Normal {};
let f = |_x: &[f64]| {};
foo(&x, &f);
}
It does not work, because f(&s[..]);
is not of type slice:
error[E0308]: mismatched types
--> src/main.rs:12:10
|
12 | f(&s[..]);
| ^^ expected usize, found struct `std::ops::RangeFull`
|
= note: expected type `usize`
found type `std::ops::RangeFull`
error[E0308]: mismatched types
--> src/main.rs:12:7
|
12 | f(&s[..]);
| ^^^^^^ expected slice, found associated type
|
= note: expected type `&[f64]`
found type `&<U as std::ops::Index<usize>>::Output`
Upvotes: 2
Views: 497
Reputation: 431649
You say that you are going to index your slice with a usize
:
U: std::ops::Index<usize>,
Then you index the slice by something that is not a usize
:
f(&s[..]);
This is a RangeFull
. Rightly, the compiler doesn't allow you to lie to it about types.
Instead, if you use the correct types, as shown in the error message, it works:
U: std::ops::Index<std::ops::RangeFull>,
Then the error is about the output type of the indexing. See Requiring implementation of Mul in generic function for a full description.
U: std::ops::Index<std::ops::RangeFull, Output = [f64]>,
That being said...
U
. Instead, add trait bounds on the associated type of D
.use std::ops::{Index, RangeFull};
pub fn foo<D, F>(dist: &D, f: F)
where
D: Distribution,
D::T: Index<RangeFull, Output = [f64]>,
F: Fn(&[f64]),
{
let s = dist.sample();
f(&s[..]);
}
Or equivalently:
pub fn foo<D>(dist: &D, f: impl Fn(&[f64]))
where
D: Distribution,
D::T: std::ops::Index<std::ops::RangeFull, Output = [f64]>,
However, using RangeFull
for this level of generic doesn't feel right to me. I'd use AsRef
instead:
pub fn foo<D>(dist: &D, f: impl Fn(&[f64]))
where
D: Distribution,
D::T: AsRef<[f64]>,
{
let s = dist.sample();
f(s.as_ref());
}
Upvotes: 8