rust 为什么.collect()有时推断Vec,但其他时候推断&Vec?

knsnq2tg  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(160)

我有以下代码片段:

1.递归地获取Vec的第n个元素

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>

Rust Playground

8ftvxx2r

8ftvxx2r1#

在第二个例子中,collect可以返回任何实现FromIterator<Self::Item>的东西(这里的Self::ItemT)。所以编译器试图通过查看tail的使用方式来猜测它的类型。当您调用helper (tail, …)时,编译器猜测tail应该与helper的第一个参数具有相同的类型,对于某些未知类型U,也称为&Vec<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));
}

Playground

disho6za

disho6za2#

问题是:

**示例1:**调用递归函数,

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

**示例2:**调用递归函数:

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

tail更改为&tail,一切正常。目前我不能确切地解释为什么,所以我会等待接受这是正确的答案,并希望其他人可以完全回答它。
Rust Playground

相关问题