我有返回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
签名以接受包含Path
和PathBuf
的切片?
答案 0 :(得分:5)
是否可以在没有内存分配的情况下将
Vec<PathBuf>
转换为&[&Path]
?
不,正如How do I write a function that takes both owned and non-owned string collections?所回答的那样; PathBuf
和Path
有不同的内存布局(答案使用String
和str
;概念是相同的。)
如何更改
f
签名以接受Path
和PathBuf
的切片?
再次按照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);
}
这不需要额外的堆分配。
答案 1 :(得分: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
,这只是堆栈上的几个指针 - 它不必实际复制任何路径。
答案 2 :(得分:0)
在没有任何分配的情况下进行投射是不可能的,因为它们在内存中的布局是不同的。
Vec<PathBuf>
以内联方式存储数据,[&Path]
存储指向数据的指针(与Vec<&PathBuf>
大致相似)。
您需要创建一个新的向量来保存指针。如果在编译时已知大小,则可以使用堆栈分配的数组。否则,需要map
+ collect
。