IntoIterator в качестве аргумента функции не принимает структуру адаптера - PullRequest
1 голос
/ 29 сентября 2019

Я хочу иметь функцию, которая принимает &IntoIterator<Item=u32>, чтобы я мог передать ей как &Vec<u32>, так и структуры адаптера итераторов (например, Map, Filter и любые другие, которые, я считаю, все реализуют IntoIterator)

Итак, у меня есть такая функция, как

pub fn f<'a, T>(it_src: &'a T) -> u32
where &'a T: IntoIterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32;
    // more more usage
    result
}

И вот как я пытался использовать ее (та же подпись, но другое имя)

pub fn f_with_feature()<'a, T>(it_src: &'a T) -> u32
where &'a T: IntoIterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(&adjusted_values)
}

У меня есть ошибка

 error[E0308]: mismatched types
  --> src\main.rs:14:7
   |
14 |     f(&adjusted_values)
   |       ^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::iter::Map`
   |
   = note: expected type `&T`
              found type `&std::iter::Map<<&T as std::iter::IntoIterator>::IntoIter, [closure@src\main.rs:13:14: 13:27]>`

Как получается, что Map не соответствует T?

Кроме того, у меня возникла идея, что прохождение итераторовАдаптеры со статической диспетчеризацией не очень хорошая идея, поскольку закрытие друг друга, используемое для создания карты, создаст новую специализацию функции. Хотя я видел, что подход статической диспетчеризации в большинстве случаев является идиоматическим в Rust. Как справиться с этой ситуацией?

1 Ответ

1 голос
/ 29 сентября 2019

Я думаю, вы хотите иметь границы черт на T (а не на &'a T). Поэтому я думаю, что вы действительно хотите следующее:

pub fn f<'a, T>(it_src: &'a T) -> u32
where T: IntoIterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32 = 1;
    // more more usage
    result
}

pub fn f_with_feature<'a, T>(it_src: &'a T) -> u32
where T: IntoIterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(&adjusted_values)
}

, что приводит нас к следующей проблеме: IntoIterator s into_iter потребляет self, что означает, что вы не можете позвонить it_src.into_iter, если вытолько заимствовать it_src.

Так что, если вы действительно хотите использовать into_iter, вы можете попробовать это:

pub fn f<T>(it_src: T) -> u32
where T: IntoIterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32 = 1;
    // more more usage
    result
}

pub fn f_with_feature<T>(it_src: T) -> u32
where T: IntoIterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(adjusted_values)
}

Выше, однако, требуется переместить значения в f соотв. f_with_feature.

По моему опыту, просто использование итератора (и, при необходимости, преобразование на сайте вызова) приводит к простым, простым решениям:

pub fn f<T>(it_src: T) -> u32
where T: Iterator<Item = u32> {
    let it = it_src.into_iter();
    let result: u32 = 1;
    // more more usage
    result
}

pub fn f_with_feature<T>(it_src: T) -> u32
where T: Iterator<Item = u32> {
    let adjusted_values = it_src.into_iter()
        .map(|e| adjust(e));
    f(adjusted_values)
}
...