【问题标题】:Collecting to a Vec vs &Vec收集到 Vec 与 &Vec
【发布时间】:2020-01-21 08:11:52
【问题描述】:

我有以下代码-sn-ps(不要质疑它们的意义;))

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&lt;T&gt;,而在第二个示例中,tail 变量的类型为 &amp;Vec&lt;?&gt;

问题:

  • 为什么?为什么返回两种不同类型的确切代码行?
  • 如何在第二个示例中返回Vec&lt;T&gt;

Rust Playground

【问题讨论】:

  • 旁注:我知道您只是将其作为练习,但请注意(以及对于未来的读者)仍然有用的是,将切片作为参数而不是不可变的更惯用引用Vec
  • 是什么让你觉得这两个变量有不同的类型?第二个示例根本无法编译,可以通过在对helper() 的调用中将tail 更改为&amp;tail 来修复。
  • @justinas 大声笑...你是对的,当我在 IntelliJ 中修改对 return helper(&amp;tail, accumulator + 1) 的帮助程序调用时,尾部的“类型”更改为 Vec&lt;T&gt;。但是我还是不明白,为什么let tail ...之后的那一行对let tail...那一行有影响
  • @SvenMarnach IntelliJ 说。它以某种方式解析类型。
  • @SleepyX667 你能用一个最小的例子创建一个Playground link,这样每个人都在同一个页面上并观察你所做的同样的事情

标签: generics vector rust vec


【解决方案1】:

在您的第二个示例中,collect can return anything that implements FromIterator&lt;Self::Item&gt;(这里的Self::ItemT)。所以编译器试图通过查看它的使用方式来猜测tail 的类型。当您调用helper (tail, …) 时,编译器猜测tail 应该与helper 的第一个参数具有相同的类型,也就是&amp;Vec&lt;U&gt; 对于一些未知类型U。然而,&amp;Vec&lt;U&gt; 确实没有实现FromIterator&lt;T&gt;,所以编译器此时退出。

OTOH 当您调用helper (&amp;tail, …) 时,编译器猜测&amp;tail 对于某些U 应该具有&amp;Vec&lt;U&gt; 类型,因此tail 应该具有Vec&lt;U&gt; 类型。然后编译器可以继续并确定U==T,它给出了tail 的完整类型为Vec&lt;T&gt;


顺便说一句,这里是您的第一个 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

【讨论】:

  • here 是一个更惯用的实现
  • @Stargateur:我得到了:error[E0658]: subslice patterns are unstable,如果我不使用 nighly 频道的话。
  • @SleepyX667 所以使用this,我使用的功能刚刚在 rustc 1.42 中稳定下来。这并没有太大变化,我的代码的重点是减少无用变量的使用。
【解决方案2】:

问题是:

示例1:调用递归函数

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

示例 2: 调用递归函数:

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

tail 更改为&amp;tail 一切正常。 目前我无法确切解释原因,所以我会等待接受这个作为正确答案,并希望其他人能够完全回答。

Rust Playground

【讨论】:

  • “一切正常”,我迫不及待地想试试像 10000 元素这样的向量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-28
  • 2022-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多