我有一个结构体,看起来像这样:
pub struct MyConfig<P>
{
// Path to file
pub file_path: P,
// Other settings
pub setting1: u8,
// [...]
}
impl <P: AsRef<Path> + std::fmt::Debug> MyConfig<P>
{
pub fn with_path(file_path:: P) -> Result<Self>
{
MyConfig
{
file_path,
setting1: 1
}
}
}
我需要一种方法来克隆配置对象。我不能只是#[derive(Clone)]
,因为P
trait绑定。我尝试手动实现Clone
,但我找不到一种方法来创建file_path
属性的通用副本/克隆。例如,为什么这不起作用:
impl <P: AsRef<Path> + std::fmt::Debug> Clone for MyConfig<P>
{
fn clone(&self) -> Self {
Self { file_path: Path::new(self.file_path.as_ref().file_name()),
setting1: self.setting1.clone(),
}
}
}
我是Rust的新手,所以也许这是一个非常愚蠢的问题(或实现),但我真的对这个看似微不足道的问题束手无策!
2条答案
按热度按时间cczfrluj1#
AsRef<Path>
的目的是让你的 * 公共函数 * 更可用,这样你就可以用&str
、String
、&Path
和PathBuf
类型的值来调用它们。但是没有理由持有如此通用的值。如果您是新手并且不确定AsRef<Path>
的开始是什么,那么这一点更加适用-在这种情况下,在公共API中接受AsRef<Path>
,并立即将其转换为PathBuf
:Playground
通过这种方式,您可以获得一个完全拥有的对象,该对象可以派生
Clone
和Debug
。高级用法备注:当您无条件地创建
PathBuf
时,您也可以接受file_path: impl Into<PathBuf>
,并使用file_path.into()
创建pathbuf。这将像AsRef<Path>
一样接受类似的类型选择,但如果调用者传递的是自己拥有的String
或PathBuf
,则将避免重新分配。该技术用于例如。通过fs_err crate来避免不必要的分配。jmp7cifd2#
AsRef
是一个trait,用于封装对底层对象的引用的类型。例如,AsRef<Path>
由&Path
、PathBuf
、Rc<Path>
、Arc<Path>
等实现。当你不关心一个类型是被借用的还是被拥有的时候,这是很方便的。然而,
AsRef<T>
不一定是可克隆的:例如,&mut T
就不是。您可以要求您的
P
实现Clone
,以便您的结构实现Clone
,这将解决您的即时编译错误:但请记住,如果
P
是一个引用,它的克隆也将是。MyConfig
的克隆将只保留引用的副本,而没有所有权。这可能是,也可能不是你想要的。由于clone()
要求您返回Self
-与被克隆的结构具有相同泛型参数的结构,因此您无法使用标准Clone
trait来解决这个问题,并且必须使用不同的方法或trait来实现这种“深度复制”。