I have a struct that looks like this:
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
}
}
}
I need a way to clone that config object. I can't just #[derive(Clone)]
, because of the P
trait bound. I tried implementing Clone
manually, but I can't find a way to make a generic copy/clone of the file_path
property. For example, why does this not work:
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(),
}
}
}
I'm quite new to Rust, so maybe this is a really dumb question (or implementation), but I'm really at my wits' end with this - seemingly trivial - problem!
The point of AsRef<Path>
is to make your public functions more usable, so you can invoke them with values of types &str
, String
, &Path
, and PathBuf
. But there is no reason to hold a value so generic. This applies doubly if you're a novice and unsure of what AsRef<Path>
does to begin with - in that case, accept AsRef<Path>
in the public API, and immediately convert it to PathBuf
:
#[derive(Debug, Clone)]
pub struct MyConfig {
// Path to file
pub file_path: PathBuf,
// Other settings
pub setting1: u8,
// [...]
}
impl MyConfig {
pub fn with_path(file_path: impl AsRef<Path>) -> Self {
MyConfig {
file_path: file_path.as_ref().to_owned(),
setting1: 1,
}
}
}
This way you get a fully owned object that can derive Clone
and Debug
.
Remark for advanced usage: When you unconditionally create PathBuf
, you can alternatively accept file_path: impl Into<PathBuf>
, and create the pathbuf with file_path.into()
. This will accept a similar choice of types like AsRef<Path>
does, but will avoid a reallocation if the caller passes an owned String
or PathBuf
. This technique is used e.g. by the fs_err crate to avoid unnecessary allocation.