Die test
Funktion erfordert diese Art F
Foo<'a>
implementiert. Die 'a
gibt es einen Lebensdauerparameter, der an die Funktion übergeben wird. Lebensdauerparameter stellen immer Lebensdauern dar, die länger leben als der Funktionsaufruf - weil es keinen Weg gibt, wie ein Anrufer eine Referenz mit einer kürzeren Lebenszeit liefern könnte; Wie können Sie einen Verweis auf eine lokale Variable von eine andere Funktion übergeben? - und für die Zwecke der Borrow-Prüfung (die lokal für eine Funktion ist), betrachtet der Compiler, dass das Borrow den gesamten Funktionsaufruf abdeckt.
Deshalb, wenn Sie eine Instanz von F
aus dem Aufruf von Foo::new
erstellen, erstellen Sie ein Objekt, das 'a
etwas mit Lebenszeit leiht, ein Leben lang, die den gesamten Funktionsaufruf abdeckt.
Es ist wichtig zu verstehen, dass, wenn Sie test::<FooS>
nennen, der Compiler füllt tatsächlich im Leben Parameter für FooS<'a>
, so dass Sie am Ende test::<FooS<'a>>
Aufruf, wo 'a
die Region ist, der die Anweisung umfasst, die den Funktionsaufruf enthält (weil &mut a
ist ein temporärer Ausdruck). Daher denkt der Compiler, dass der FooS
, der in test
konstruiert würde, etwas bis zum Ende der Anweisung mit dem Aufruf an test
ausleihen würde!
Lassen Sie sich Kontrast dies mit der nicht-generischen Version:
let mut foo = FooS {data: data};
In dieser Version wählt der Compiler eine konkrete Lebenszeit für FooS<'a>
in test
, anstatt in main
, so wird es den Block Suffix vom Ende erstreckt wählen der let
Anweisung an das Ende des Blocks, was bedeutet, dass der nächste Kredit von data
nicht überlappt und es gibt keinen Konflikt.
Was Sie wirklich wollen, ist, dass F
Foo<'x>
für einige Lebensdauer implementieren 'x
, die kürzer als 'a
ist, und was am wichtigsten ist, muss die Lebensdauer einer Region innerhalb der Funktion, nicht ein umschließt ein wie 'a
ist.
Die aktuelle Lösung von Rust für dieses Problem sind höherrangige Merkmalsgrenzen. Es sieht wie folgt aus:
fn test<'a, F>(data: &'a mut u32)
where F: for<'x> Foo<'x>
{
{
let mut foo: F = Foo::new(data);
foo.apply();
}
println!("{:?}", data);
}
In Worten, es bedeutet den Typ F
muss Foo<'x>
für jede mögliche 'x
implementieren.
Während diese Version von test
auf eigene kompiliert, können wir nicht wirklich einen Typ liefern, die diese Bedingung erfüllt, da für jede mögliche Lebensdauer 'a
gibt es einen bestimmten Typ FooS<'a>
, die nur Foo<'a>
implementiert.Wenn FooS
kein Lebensdauer Parameter hatte und die impl von Foo
für FooS
sah wie folgt aus:
impl<'a> Foo<'a> for FooS {
dann wäre es in Ordnung sein, da es eine einzige Art ist, die FooS
'a
Foo<'a>
für jede mögliche Lebensdauer implementiert.
Natürlich können Sie den Lebensdauerparameter FooS
nicht entfernen, da er einen ausgeliehenen Zeiger enthält. Die richtige Lösung für dieses Problem ist eine Funktion, die Rust noch nicht hat: die Fähigkeit, einen Typkonstruktor (anstelle eines vollständig konstruierten Typs) als generischen Parameter an eine Funktion zu übergeben. Mit dieser Funktion könnten wir test
mit FooS
aufrufen, einen Typenkonstruktor, der einen Lebensdauerparameter benötigt, um einen konkreten Typ zu erzeugen, ohne die konkrete Lebensdauer am Aufrufort anzugeben, und der Aufrufer könnte seine eigene Lebensdauer bereitstellen.
https://play.rust-lang.org/?gist=dabe17d66a14e72c2ca67e064ca26601&version=nightly&backtrace=0 funktioniert. so ... – Jacob
Trotzdem scheint dies ein Fehler zu sein. – JDemler