Цепной вектор и элемент IntoIterator в Rust - PullRequest
0 голосов
/ 14 октября 2019

Я хочу написать функцию в Rust, которая будет возвращать вектор, состоящий из начального целого числа, затем всех промежуточных целых чисел и затем конечного целого числа. Утверждение, которое оно должно содержать, таково:

assert_eq!(intervals(0, 4, 1..4), vec![0, 1, 2, 3, 4]);

Подсказка - использовать цепной метод для итераторов . Объявление функции предопределено, я реализовал его одним способом, а именно следующим кодом:

pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
    I: IntoIterator<Item = u32>,
{
    let mut a1 = vec![];
    a1.push(start);

    let inter: Vec<u32> = intermediate.into_iter().collect();
    let mut iter : Vec<u32> = a1.iter().chain(inter.iter()).map(|x| *x).collect();

    iter.push(end);
    return iter;
}

Но я совершенно уверен, что это не совсем оптимальный способ сделать это. Я уверен, что я делаю много ненужных вещей в средних двух строках. Я пытался использовать промежуточное напрямую, как это:

let mut iter: Vec<u32> = a1.iter().chain(intermediate).map(|x| *x).collect();

Но я получаю эту ошибку для цепного метода, и я не знаю, как ее решить:

type mismatch resolving <I as std::iter::IntoIterator>::Item==&u32, 
expected u32, found &u32

Я суперНовое в Rust, поэтому любой совет будет полезен, чтобы понять, как правильно использовать здесь промежуточный параметр.

1 Ответ

4 голосов
/ 14 октября 2019

Вот несколько советов:

  • Вы создали три отдельных вектора (один явно, два с использованием collect), когда на самом деле вам нужен только один.
  • Вы можетеиспользуйте итератор std::iter::once для создания итераторов для начальных и конечных целых чисел
  • Нет необходимости собирать промежуточный диапазон. Аргумент intermediate реализует IntoIterator, поэтому вы можете передать его непосредственно в chain. Таким образом, вы можете связать воедино начало, промежуточное и конечное значения.
  • Нет необходимости использовать ключевое слово return в конце функции - результатом функции является значение последнего выражения в ней (до тех пор, пока на конце нет точки с запятой).

При использовании этих советов ваша функция будет выглядеть следующим образом:

use std::iter::once;

pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
    I: IntoIterator<Item = u32>,
{
    once(start).chain(intermediate).chain(once(end)).collect()
}

Еще одна вещь, на которую следует обратить внимание, чтобы ответить на ваш вопросиз комментариев:

зачем пытаться это: a1.iter (). chain (промежуточный) выдает ошибку с методом цепочки

Вызов Vec::iter() возвращает итератор, которыйвозвращает ссылки на значения в векторе. Это имеет смысл: вызов iter() не использует вектор, а его содержимое остается нетронутым: вы можете перебирать его несколько раз, если хотите.

С другой стороны, вызывая into_iter() из IntoIterator trait возвращает итератор, который возвращает значения . Это также имеет смысл: into_iter() действительно потребляет объект, для которого вы его вызываете, поэтому итератор затем становится владельцем элементов, которые ранее принадлежали этому объекту.

Попытка связать вместе два таких итератора не даетработать, потому что каждый из них повторяет разные типы. Одним из разрешений было бы также использование a1, например:

let mut iter : Vec<u32> = a1.into_iter().chain(intermediate).collect();
...