如何编写存储“路径”的构建器?

时间:2015-11-06 15:01:46

标签: path rust borrowing

Path参数可以立即转换为PathBuf,但这似乎效率低下。必须有一些方法来保持Path,对吗?

use std::fs::File;
use std::path::Path;

struct Foo {
    a: Option<File>,
    b: Option<File>,
}
struct FooBuilder<'a> {
    a: Option<&'a Path>,
    b: Option<&'a Path>
}
impl<'a> FooBuilder<'a> {
    fn new() -> FooBuilder<'a> {
        FooBuilder {
            a: None,
            b: None,
        }
    }
    fn a<P: AsRef<Path>+'a>(&'a mut self, a: P) -> &mut FooBuilder<'a> {
        self.a = Some(a.as_ref());
        self
    }
    fn b<P: AsRef<Path>+'a>(&'a mut self, b: P) -> &mut FooBuilder<'a> {
        self.b = Some(b.as_ref());
        self
    }
    fn done(&self) -> Foo {
        Foo {
            a: match self.a {
                Some(path) => Some(File::open(path).unwrap()),
                None => None,
            },
            b: match self.b {
                Some(path) => Some(File::open(path).unwrap()),
                None => None,
            }
        }
    }
}

fn main() {
    let path1 = Path::new("1");
    let path2 = Path::new("2");
    let foo = FooBuilder::new().a(path1).b(path2).done();
}

1 个答案:

答案 0 :(得分:1)

这有效:

use std::fs::File;
use std::path::Path;

struct Foo {
    a: Option<File>,
}

struct FooBuilder<'a> {
    a: Option<&'a Path>,
}

impl<'a> FooBuilder<'a> {
    fn new() -> FooBuilder<'a> {
        FooBuilder {
            a: None,
        }
    }

    fn a<P: ?Sized>(&mut self, a: &'a P) -> &mut FooBuilder<'a> 
        where P: AsRef<Path>
    {
        self.a = Some(a.as_ref());
        self
    }

    fn build(&self) -> Foo {
        Foo {
            a: self.a.map(|path| File::open(path).unwrap()),
        }
    }
}

fn main() {
    let path1 = Path::new("1");
    let foo = FooBuilder::new().a(path1).build();
}

让我们关注a方法:

fn a<P: ?Sized>(&mut self, a: &'a P) -> &mut FooBuilder<'a> 
    where P: AsRef<Path>

此方法接受引用到实现AsRef<Path>的类型。这意味着我们可以获得与Path的引用,其生命周期与参数相同。另一个更改是通过Sized使?绑定为类型的可选项。这意味着我们可以参考一些我们不知道它有多大的东西。这很好,因为我们知道引用本身有多大。

让我们将其与原始版本进行比较:

fn a<P: AsRef<Path>+'a>(&'a mut self, a: P) -> &mut FooBuilder<'a> {
    self.a = Some(a.as_ref());
    self
}

此处,a参数按值传递到方法a。当您调用as_ref时,您隐式在引用上将其调用到方法调用的堆栈帧上的项目。引用项将在方法调用结束时被删除,这意味着引用将变为无效。这就是你得到error: `a` does not live long enough错误背后的原因。

我还使用Option::map来清理build方法。我将其重命名为build,因为构建器通常应该使用build方法,除非使用更明显的动词(如open)。< / p>