Сбор к Ve c против & Vec - PullRequest
       19

Сбор к Ve c против & Vec

0 голосов
/ 21 января 2020

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

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

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. получить длину Ve c рекурсивно

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> во втором примере?

Rust Playground

Ответы [ 2 ]

2 голосов
/ 21 января 2020

Во втором примере 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>.


В качестве отступления, здесь приведена более идиоматическая c реализация вашего первый 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));
}

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

0 голосов
/ 21 января 2020

Проблема в следующем:

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

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

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

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

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

Rust Playground

...