我如何接受可以通过`..`切割的任意容器?

The*_*son 2 rust

我有以下简单的设置:

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)

She*_*ter 7

你说你打算用你的切片索引usize:

U: std::ops::Index<usize>,
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过不是usize:

f(&s[..]);
Run Code Online (Sandbox Code Playgroud)

这是一个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)

话虽如此...

  1. 没有理由引入泛型类型U.相反,在相关类型上添加特征边界D.
  2. 您不太可能强制动态发送关闭.相反,将其作为通用类型:
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)