1

Path引数はすぐに に変換できますが、PathBuf効率が悪いようです。だけを維持する方法が必要Pathですよね?

use std::{fs::File, 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();
}
error[E0597]: `a` does not live long enough
  --> src/main.rs:19:23
   |
13 | impl<'a> FooBuilder<'a> {
   |      -- lifetime `'a` defined here
...
19 |         self.a = Some(a.as_ref());
   |         --------------^----------
   |         |             |
   |         |             borrowed value does not live long enough
   |         assignment requires that `a` is borrowed for `'a`
20 |         self
21 |     }
   |     - `a` dropped here while still borrowed

error[E0597]: `b` does not live long enough
  --> src/main.rs:24:23
   |
13 | impl<'a> FooBuilder<'a> {
   |      -- lifetime `'a` defined here
...
24 |         self.b = Some(b.as_ref());
   |         --------------^----------
   |         |             |
   |         |             borrowed value does not live long enough
   |         assignment requires that `b` is borrowed for `'a`
25 |         self
26 |     }
   |     - `b` dropped here while still borrowed
4

1 に答える 1

2

これは機能します:

use std::{fs::File, 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>(&mut self, a: &'a P) -> &mut FooBuilder<'a>
    where
        P: AsRef<Path> + ?Sized,
    {
        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>(&mut self, a: &'a P) -> &mut FooBuilder<'a>
where
    P: AsRef<Path> + ?Sized,

このメソッドは、を実装する型への参照を受け入れますAsRef<Path>Pathこれは、パラメータと同じ有効期間を持つへの参照を取得できることを意味します。もう 1 つの変更は、 を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ため、名前を に変更しました。buildopen

以下も参照してください。

于 2015-11-06T15:36:32.347 に答える