Vec<&&str> 和 Vec<&Str> 一样吗?

Is Vec<&&str> the same as Vec<&Str>?

我正在学习 Rust,我正在尝试解决代码挑战(2015 年第 9 天)。

我创造了一种情况,我最终得到一个类型为 Vec<&&str> 的变量(请注意双“&”,这不是拼写错误)。我现在想知道这种类型是否与 Vec<&str> 不同。我无法弄清楚对某物的引用是否有意义。我知道我可以通过对 fromto 变量使用 String 来避免这种情况。我在问是否 Vec<&&str> == Vec<&str> 以及我是否应该尝试避免 Vec<&&str>.

这里是触发这个问题的代码:

use itertools::Itertools
use std::collections::{HashSet};

fn main() {
    let contents = fs::read_to_string("input.txt").unwrap();

    let mut vertices: HashSet<&str> = HashSet::new();

    for line in contents.lines() {

        let data: Vec<&str> = line.split(" ").collect();

        let from = data[0];
        let to = data[2];

        vertices.insert(from);
        vertices.insert(to);
    }

    // `Vec<&&str>` originates from here
    let permutations_iter = vertices.iter().permutations(vertices.len());

    for perm in permutations_iter {
        let length_trip = compute_length_of_trip(&perm);
    }
}

fn compute_length_of_trip(trip: &Vec<&&str>) -> u32 {
    ...
}

你有 &&str 的原因是数据 &str 由顶点拥有,当你在该数据上创建一个 interator 时,你只是获得对该数据的引用,因此 &&str.

这里真的没有什么可以避免的。它只是显示您的迭代器引用了 HashSet 中的数据。

Vec<&str> 和 Vec<&&str> 是不同类型吗?

I'm now wondering if this type is different than Vec<&str>.

是的,Vec<&&str> 是不同于 Vec<&str> 的类型 - 您不能在需要 Vec<&str> 的地方传递 Vec<&&str>,反之亦然。 Vec<&str> 存储字符串切片引用,您可以将其视为指向某些字符串内部数据的指针。 Vec<&&str> 存储对此类字符串切片引用的引用,即指向数据指针的指针。对于后者,访问字符串数据需要额外的间接访问。

然而,Rust 的自动取消引用使得 使用 成为可能 Vec<&&str> 就像你使用 Vec<&str> - 例如,v[0].len() 在任何一个上都可以正常工作, v[some_idx].chars() 将用任何一个遍历字符,依此类推。唯一的区别是 Vec<&&str> 更间接地存储数据,因此每次访问都需要做更多的工作,这可能会导致代码效率稍低。

请注意,您始终可以将 Vec<&&str> 转换为 Vec<&str> - 但由于这样做需要分配一个新向量,因此如果您决定不需要 Vec<&&str>,则更好一开始就不要创建它。

我可以避免 Vec<&&str> 吗?如何避免?

由于 &strCopy,您可以通过在遍历 vertices 时添加 .copied() 来避免创建 Vec<&&str>,即更改vertices.iter()vertices.iter().copied()。如果你不需要 vertices 坚持下去,你也可以使用 vertices.into_iter(),它会在迭代完成后立即给出 &str 以及免费的 vertices 向量完成。

附加引用的产生原因及避免方法以前

我应该避免使用 Vec<&&str> 吗?

Vec<&&str> 本身并没有什么需要避免的错误。在大多数代码中,您永远不会注意到 Vec<&&str>Vec<&str> 之间的效率差异。话虽如此,除了微基准测试的性能之外,还有一些原因可以避免它。 Vec<&&str> 中的附加间接需要确切的 &strs 从中创建(而不仅仅是拥有数据的字符串)来保留并比新集合更有效。这与您的情况无关,但如果您想 return 对拥有字符串的调用者进行排列,这会变得很明显。此外,不在每个转换上累积引用的更简单类型也有其价值。试想一下需要将 Vec<&&str> 进一步转换为一个新的向量 - 你不想处理 Vec<&&&str>,等等每个新的转换。

关于性能,较少的间接性通常更好,因为它避免了额外的内存访问并增加了数据局部性。但是,还应该注意 Vec<&str> 每个元素占用 16 个字节(在 64 位体系结构上),因为切片引用由“胖指针”表示,即 pointer/length 对。另一方面,Vec<&&str>(以及 Vec<&&&str> 等)每个元素仅占用 8 个字节,因为对胖引用的引用由常规的“瘦”指针表示。因此,如果您的矢量测量数百万个元素,则 Vec<&&str> 可能比 Vec<&str> 更高效 ,因为它占用的内存更少。一如既往,如有疑问,请测量。