Es gibt zwei Lösungen für Ihr Problem. Beginnen wir mit dem einfachsten anfangen:
ein Leben lang zu Ihrer Eigenschaft hinzufügen
trait Foo<'a> {
type Item: AsRef<Path>;
type Iter: Iterator<Item = Self::Item>;
fn get(&'a self) -> Self::Iter;
}
Dies erfordert, dass Sie die Lebensdauer zu annotieren überall Sie das Merkmal verwenden. Wenn Sie das Merkmal implementieren, müssen Sie eine generische Implementierung tun:
impl<'a> Foo<'a> for Bar {
type Item = &'a PathBuf;
type Iter = std::slice::Iter<'a, PathBuf>;
fn get(&'a self) -> Self::Iter {
self.v.iter()
}
}
Wenn Sie das Merkmal für ein generisches Argument benötigen, müssen Sie auch sicherstellen, dass alle Verweise auf Ihre Eigenschaft Objekt die gleiche Lebensdauer haben:
fn fooget<'a, T: Foo<'a>>(foo: &'a T) {}
implementieren sie die Eigenschaft für einen Verweis auf Ihre Art
Anstatt das Merkmal für Ihre Art der Umsetzung implementieren es für einen Verweis auf Ihre Art. Das Merkmal muss auf diese Weise nie etwas über die Lebenszeit wissen.
Die Merkmalsfunktion muss dann ihr Argument nach Wert übernehmen. In Ihrem Fall werden Sie das Merkmal für eine Referenz implementieren:
trait Foo {
type Item: AsRef<Path>;
type Iter: Iterator<Item = Self::Item>;
fn get(self) -> Self::Iter;
}
impl<'a> Foo for &'a Bar {
type Item = &'a PathBuf;
type Iter = std::slice::Iter<'a, PathBuf>;
fn get(self) -> Self::Iter {
self.v.iter()
}
}
Ihre fooget
Funktion jetzt wird einfach
fn fooget<T: Foo>(foo: T) {}
Das Problem dabei ist, dass die fooget
Funktion nicht T
in Wirklichkeit ein weiß ist &Bar
. Wenn Sie die get
Funktion aufrufen, bewegen Sie sich tatsächlich aus der Variablen foo
heraus. Sie bewegen sich nicht aus dem Objekt heraus, Sie verschieben nur die Referenz. Wenn Ihre fooget
Funktion versucht, get
zweimal aufzurufen, wird die Funktion nicht kompiliert.
Wenn Sie Ihre fooget
Funktion wollen nur Argumente akzeptieren, wenn das Foo
Merkmal für Referenzen implementiert ist, müssen Sie ausdrücklich darauf hinweisen diese Schranke:
fn fooget_twice<'a, T>(foo: &'a T)
where
&'a T: Foo,
{}
Die where
Klausel stellt sicher, dass Sie nur diese Funktion aufrufen für Referenzen, wo Foo
für die Referenz anstelle des Typs implementiert wurde. Es kann auch für beide implementiert werden.
Technisch könnte der Compiler automatisch die Lebensdauer in fooget_twice
schließen, so schreiben Sie könnten es als
n fooget_twice<T>(foo: &T)
where
&T: Foo,
{}
aber es ist nicht klug genug yet.
Bei komplizierteren Fällen können Sie eine Rust-Funktion verwenden, die noch nicht implementiert ist: Generic Associated Types (GATS). Arbeiten dafür werden in issue 44265 verfolgt.
Ich habe gewählt, um die erste Lösung zu verwenden, da es scheinbar weniger Belastung aus der Sicht der "fooget" wie Funktionen auferlegt. Das Merkmal ist auch expliziter als die zweite Lösung. – mbrt