如何将Vec<PathBuf>转换为&[&Path],且不进行内存分配?

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的切片?


你不能只是把 f 改成 fn f(paths: &[PathBuf]) 吗?它仍然接受一个切片,所以没有额外的分配。 - Peter Hall
@PeterHall 的 f 函数签名并非偶然,我也将 Vec<&Path> 传递给它。 - user1244932
4
如果你希望它对 Path、PathBuf、Vec 和 [] 泛化,那么你可能需要采用这样的方式:T, I where T: Iterator<Item=I>, I: AsRef<Path>。请注意,在翻译过程中,我保留了原文的意思并尽可能地使其更通俗易懂,但没有添加解释或其他信息。 - the8472
3个回答

5
是否可以在不进行内存分配的情况下将Vec<PathBuf>转换为&[&Path]
不行,正如如何编写一个同时接受拥有和非拥有字符串集合的函数?所回答的那样;PathBufPath具有不同的内存布局(答案使用了Stringstr;概念相同)。
如何更改f签名以接受带有PathPathBuf的切片?
同样建议在如何编写一个同时接受拥有和非拥有字符串集合的函数?中使用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

不能仅仅进行强制类型转换而不进行任何分配,因为它们在内存中的布局是不同的。

Vec<PathBuf> 在内部存储数据,而 [&Path] 存储指向数据的指针(类似于 Vec<&PathBuf>)。

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


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,但实际上只是在堆栈上创建了一些指针 - 它不必实际复制任何路径。

从我的角度来看,大小并不重要,但在堆上的分配可能需要很长时间。我考虑过将切片更改为迭代器(几乎像您的代码,但没有collect),但仍然无法强制编译器接受我的代码,因为涉及到Sized魔法。 - user1244932
这里没有新的堆分配。只有对现有路径的引用。 - Peter Hall
让我们来看看 let paths: Vec<&Path> 这段代码,你是想问 Vec 是否在栈上分配空间? - user1244932
它正在堆上分配内存。但它只分配指针,而不是实际的数据。编译器很可能会优化掉额外的跳转。 - Peter Hall
1
这里没有新的堆分配,确实发生了堆分配。整个向量都在堆上分配!我不认为会有任何优化,因为向量是运行时概念,编译器无法通过它们进行优化。 - Shepmaster
@Shepmaster 是的,这很公平。但是没有其他方法来布置未知大小的数据内存,以创建所请求的切片。 - Peter Hall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接