VEC 到[&Path]没有分配?

问题描述 投票:2回答:3

我有返回Vec<PathBuf>的函数和接受&[&Path]的函数,基本上是这样的:

use std::path::{Path, PathBuf};

fn f(paths: &[&Path]) {
}

fn main() {
    let a: Vec<PathBuf> = vec![PathBuf::from("/tmp/a.txt"), PathBuf::from("/tmp/b.txt")];

    f(&a[..]);
}

是否可以在没有内存分配的情况下将Vec<PathBuf>转换为&[&Path]

如果没有,我应该如何更改f签名以接受PathPathBuf的切片?

reference rust slice
3个回答
5
投票

是否可以在没有内存分配的情况下将Vec<PathBuf>转换为&[&Path]

不,正如How do I write a function that takes both owned and non-owned string collections?所回答的那样;一个PathBuf和一个Path有不同的内存布局(答案使用Stringstr;概念是相同的)。

我该如何更改f签名以接受PathPathBuf的切片?

再次按照How do I write a function that takes both owned and non-owned string collections?的建议,使用AsRef

use std::path::{Path, PathBuf};

fn f<P>(paths: &[P])
    where P: AsRef<Path>
{}

fn main() {
    let a = vec![PathBuf::from("/tmp/a.txt")];
    let b = vec![Path::new("/tmp/b.txt")];

    f(&a);
    f(&b);
}

这不需要额外的堆分配。


0
投票

要传递切片,您还必须将原始数据保存在某处。要有一个&[&Path],那么这需要指向像Vec<&Path>这样的东西。但你没有其中一个,你有一个Vec<PathBuf>

要使其与现有签名一起使用,您可以制作一个临时的Vec<&Path>,然后分一杯羹。

fn f(paths: &[&Path]) {
}

fn main() {
    let a: Vec<PathBuf> = vec![PathBuf::from("/tmp/a.txt"), PathBuf::from("/tmp/b.txt")];
    let paths: Vec<&Path> = a.iter().map(PathBuf::as_path).collect();
    f(&paths[..]);

}

即使这会创建一个新的Vec,这只是堆栈上的几个指针 - 它不必实际复制任何路径。


0
投票

在没有任何分配的情况下进行投射是不可能的,因为它们在内存中的布局是不同的。

Vec<PathBuf>将数据存储为内联,[&Path]存储指向数据的指针(它与Vec<&PathBuf>大致相似)。

您需要创建一个新的向量来保存指针。如果在编译时已知大小,则可以使用堆栈分配的数组。否则需要map + collect

© www.soinside.com 2019 - 2024. All rights reserved.