Как я могу принять произвольный контейнер, который можно разрезать на `..`? - PullRequest
0 голосов
/ 05 июля 2018

У меня есть следующие простые настройки:

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`

1 Ответ

0 голосов
/ 05 июля 2018

Вы говорите, что собираетесь проиндексировать свой фрагмент с usize:

U: std::ops::Index<usize>,

Затем вы индексируете срез чем-то, что не usize:

f(&s[..]);

Это RangeFull. Правильно, компилятор не позволяет вам лгать о типах.

Вместо этого, если вы используете правильные типы, как показано в сообщении об ошибке, это работает:

U: std::ops::Index<std::ops::RangeFull>,

Тогда ошибка касается типа вывода индексации. См. Требование реализации Mul в универсальной функции для полного описания.

U: std::ops::Index<std::ops::RangeFull, Output = [f64]>,

Как говорится ...

  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[..]);
}

или эквивалентно:

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());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...