Сбор в Vec vs & Vec

У меня есть следующие фрагменты кода (не сомневайтесь в их смысле;))

1. рекурсивно получить n-й элемент Vec

fn helper<T: Clone>(n: usize, current_n: usize, current_xs: &Vec<T>, accumulator: Option<T>) -> Option<T> {
    if current_n > n {
        accumulator
    } else {
        let head = current_xs.get(0).cloned();
        let tail = current_xs.clone().into_iter().skip(1).collect();
        return helper(n, current_n + 1, &tail, head);
    }
}

2. рекурсивно получить длину Vec

fn helper<T: Clone>(current_xs: &Vec<T>, accumulator: usize) -> usize {
    if current_xs.is_empty() {
        accumulator
    } else {
        let tail = current_xs.clone().into_iter().skip(1).collect();
        return  helper(tail, accumulator + 1)
    }
}

Мой вопрос об этой строке:

let tail = current_xs.clone().into_iter().skip(1).collect();

В первом примере tail переменная типа Vec<T> а во втором примере tail переменная имеет тип &Vec<?>.

Вопросы:

  • Зачем? Почему возвращает точную строку кода двух разных типов?
  • Как я могу вернуть Vec<T> во втором примере?

Ржавчина Детская площадка

2 ответа

Решение

Во втором примере collect может вернуть все, что реализует FromIterator<Self::Item> (Вот Self::Item является T). Таким образом, компилятор пытается угадать типtailглядя на то, как это используется. Когда ты звонишьhelper (tail, …), компилятор догадывается, что tail должен иметь тот же тип, что и первый аргумент для helper, иначе &Vec<U> для какого-то еще неизвестного типа U. Однако,&Vec<U>никак не реализоватьFromIterator<T>, поэтому на этом этапе компилятор выходит из строя.

OTOH при звонке helper (&tail, …), компилятор догадывается, что &tail должен иметь тип &Vec<U> для некоторых U, и поэтому tail должен иметь тип Vec<U>. Затем компилятор может продолжить и определить, чтоU==T, что дает полный вид tail как Vec<T>.


В стороне, вот более идиоматическая реализация вашего первого helperэто позволяет избежать ненужных копий. Что-то подобное можно сделать и для второго:

fn helper<T: Clone> (n: usize, current_n: usize, current_xs: &[T], accumulator: Option<&T>) -> Option<T> 
{
    if current_n > n {
        accumulator.cloned()
    } else {
        let head = current_xs.get (0);
        let tail = &current_xs[1..];
        return if tail.is_empty() { 
            None
        } else {
            helper (n, current_n + 1, tail, head)
        };
    }
}

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    println!("Element 3: {:?}", helper (3, 0, &v, None));
    println!("Element 10: {:?}", helper (10, 0, &v, None));
}

Детская площадка

Проблема в:

Пример 1: вызывает рекурсивную функцию с

return helper(n, current_n + 1, &tail, head); // &tail

Пример 2: вызывает рекурсивную функцию с:

return  helper(tail, accumulator + 1) // tail

Изменение tail к &tailвсе работает. На данный момент я не могу точно объяснить, почему, поэтому я бы подождал, чтобы принять это как правильный ответ, и надеюсь, что кто-то еще сможет полностью ответить на него.

Ржавчина Детская площадка

Другие вопросы по тегам