我有以下简单设置:
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
接受一个实现Distribution
和一个功能的通用容器,但是如果我在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);
}
它不起作用,因为f(&s[..]);
的类型不是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`
答案 0 :(得分:6)
您说您将使用usize
索引切片:
U: std::ops::Index<usize>,
然后,您使用不是usize
的内容对切片进行索引:
f(&s[..]);
这是RangeFull
。正确,编译器不允许您对类型撒谎。
相反,如果您使用正确的类型(如错误消息中所示),它将起作用:
U: std::ops::Index<std::ops::RangeFull>,
然后,该错误与索引的输出类型有关。有关完整说明,请参见Requiring implementation of Mul in generic function。
U: std::ops::Index<std::ops::RangeFull, Output = [f64]>,
话虽如此...
U
。而是在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[..]);
}
或等效地:
pub fn foo<D>(dist: &D, f: impl Fn(&[f64]))
where
D: Distribution,
D::T: std::ops::Index<std::ops::RangeFull, Output = [f64]>,
但是,对这种通用级别使用RangeFull
并不适合我。我会改用AsRef
:
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());
}