我有以下简单的设置:
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[..]);
}
Run Code Online (Sandbox Code Playgroud)
foo
接受了实现通用容器Distribution
和功能,但如果我用它像一个例子这样:
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);
}
Run Code Online (Sandbox Code Playgroud)
它不起作用,因为f(&s[..]);
它不是切片类型:
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`
Run Code Online (Sandbox Code Playgroud)
你说你打算用你的切片索引usize
:
Run Code Online (Sandbox Code Playgroud)U: std::ops::Index<usize>,
然后,您可以通过不是usize
:
Run Code Online (Sandbox Code Playgroud)f(&s[..]);
这是一个RangeFull
.正确地说,编译器不允许你对类型撒谎.
相反,如果您使用正确的类型,如错误消息中所示,它可以工作:
U: std::ops::Index<std::ops::RangeFull>,
Run Code Online (Sandbox Code Playgroud)
然后错误是关于索引的输出类型.有关完整说明,请参阅在通用函数中要求实现Mul.
U: std::ops::Index<std::ops::RangeFull, Output = [f64]>,
Run Code Online (Sandbox Code Playgroud)
话虽如此...
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[..]);
}
Run Code Online (Sandbox Code Playgroud)
或等效地:
pub fn foo<D>(dist: &D, f: impl Fn(&[f64]))
where
D: Distribution,
D::T: std::ops::Index<std::ops::RangeFull, Output = [f64]>,
Run Code Online (Sandbox Code Playgroud)
但是,使用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());
}
Run Code Online (Sandbox Code Playgroud)