Warum kann ich nicht speichern Sie einen Wert und eine Referenz auf den Wert in der gleichen Struktur?
Ich habe einen Wert und ich möchte speichern, dass Wert und eine Referenz auf
etwas im inneren, dass Wert auf meine eigene Art:
struct Thing {
count: u32,
}
struct Combined<'a>(Thing, &'a u32);
fn make_combined<'a>() -> Combined<'a> {
let thing = Thing { count: 42 };
Combined(thing, &thing.count)
}
Manchmal, ich habe einen Wert und ich möchte speichern, dass Wert und eine Referenz auf
diesen Wert in der gleichen Struktur:
struct Combined<'a>(Thing, &'a Thing);
fn make_combined<'a>() -> Combined<'a> {
let thing = Thing::new();
Combined(thing, &thing)
}
Manchmal bin ich auch nicht nehmen, eine Referenz für den Wert und bekomme ich die
gleicher Fehler:
struct Combined<'a>(Parent, Child<'a>);
fn make_combined<'a>() -> Combined<'a> {
let parent = Parent::new();
let child = parent.child();
Combined(parent, child)
}
In jedem dieser Fälle, bekomme ich eine Fehlermeldung, dass einer der Werte "hat
nicht lange genug Leben". Was hat dieser Fehler zu bedeuten?
Für die Letztgenannte Beispiel, eine definition der
Ich habe überlegt, dass, entschied sich dann aber dagegen basiert auf zwei miteinander verknüpften Fragen. Weder die Fragen angeschaut die definition der Struktur struct oder die Methode in Frage, so dachte ich, es wäre am besten zu imitieren, um die Menschen können leichter mit dieser Frage an Ihre eigene situation. Beachten Sie, dass tun zeigen die Signatur der Methode in der Antwort.
Parent
und Child
helfen könnte...Ich habe überlegt, dass, entschied sich dann aber dagegen basiert auf zwei miteinander verknüpften Fragen. Weder die Fragen angeschaut die definition der Struktur struct oder die Methode in Frage, so dachte ich, es wäre am besten zu imitieren, um die Menschen können leichter mit dieser Frage an Ihre eigene situation. Beachten Sie, dass tun zeigen die Signatur der Methode in der Antwort.
InformationsquelleAutor Shepmaster | 2015-08-30
Du musst angemeldet sein, um einen Kommentar abzugeben.
Schauen wir uns eine einfache Implementierung dieser:
Schlägt dies fehl mit der Fehlermeldung:
Vollständig zu verstehen, dieser Fehler, den Sie haben, darüber nachzudenken, wie die
die Werte sind dargestellt in den Speicher und was passiert, wenn Sie bewegen
solche Werte. Lassen Sie uns kommentieren
Combined::new
mit einigen hypothetischenSpeicher-Adressen, die anzeigen, wo die Werte befinden sich:
Was passieren sollte
child
? Wenn der Wert wurde nur verschoben wieparent
war, dann wäre es beziehen sich auf Speicher, die nicht mehr ist garantiert
haben Sie einen gültigen Wert ein. Jedem anderen Stück code gespeichert werden dürfen
Werte im Speicher Adresse 0x1000. Der Zugriff auf diesen Speicher vorausgesetzt, es war
ein integer könnte führen zu Abstürzen und/oder security-bugs, und ist einer der
die wichtigsten Kategorien der Fehler, die Rost verhindert.
Genau das ist das problem, dass Leben verhindern. Ein Leben lang ist eine
etwas von Metadaten, mit denen Sie und der compiler wissen, wie lange ein
Wert wird gültig sein aktuellen Speicherort. Das ist ein
wichtige Unterscheidung, da es ein häufiger Fehler, den Rost Neulinge machen.
Rost-Lebensdauer nicht die Zeit zwischen, wenn Sie ein Objekt
geschaffen, und wenn es zerstört!
Als eine Analogie, denken Sie an es auf diese Weise: Während das Leben einer person, Sie wird
befinden sich an vielen verschiedenen Standorten, die jeweils mit einer eindeutigen Adresse. Ein
Rost Lebenszeit beschäftigt sich mit der Adresse, die Sie befinden sich derzeit in,
nicht etwa, wenn Sie sterben in die Zukunft (auch wenn sterben auch
änderungen Ihrer Adresse). Jedes mal, wenn Sie verschieben, es ist relevant, weil Ihre
Adresse ist nicht mehr gültig.
Es ist auch wichtig zu beachten, dass die Lebensdauer nicht den code ändern; Ihre
code steuert das Leben, Ihr Leben keinen Einfluss auf den code. Die
markige Spruch "Leben sind deskriptiv, nicht präskriptiv".
Let ' s kommentieren
Combined::new
mit einigen line-Nummern, die wir verwendenmarkieren Lebensdauer:
Den konkrete Leben von
parent
ist von 1 bis 4, inklusive (die werde ichstellen
[1,4]
). Die konkrete Lebensdauer vonchild
ist[2,4]
, unddie konkrete Lebensdauer der Rückgabewert ist
[4,5]
. Es istmöglich ist das konkrete Leben, bei null anfangen - das würde
repräsentieren Sie die Lebensdauer der parameter an eine Funktion oder etwas, dass
existierte außerhalb des Blocks.
Beachten Sie, dass die Lebensdauer von
child
selbst ist[2,4]
ist, sondern dass es bezieht sichzu einen Wert mit einer Lebensdauer von
[1,4]
. Dies ist unproblematisch, solange diebezugnehmend Wert ungültig wird, bevor die genannte-Wert hat. Die
problem tritt auf, wenn wir versuchen, wieder
child
aus dem block. Dies würde"over-extend" das Leben über seine Natürliche Länge.
Diese neuen Erkenntnisse erklären die ersten beiden Beispiele. Die Dritte
benötigt man Blick auf die Umsetzung der
Parent::child
. Chancensind, es wird in etwa so Aussehen:
Diese verwendet Lebensdauer elision zu vermeiden, schreiben explizite generic
lifetime Parameter. Es ist äquivalent zu:
In beiden Fällen die Methode sagt, dass eine
Child
Strukturzurückgegeben wurde, parametrisiert mit der konkreten Lebensdauer
self
. Mit anderen Worten, dieChild
Instanz enthält eine Referenzder
Parent
erstellt wurden, und kann so nicht länger Leben als dieParent
Instanz.Dies lässt uns auch erkennen, dass etwas wirklich falsch mit unserer
Erstellung Funktion:
Obwohl Sie sind eher zu sehen, geschrieben in einer anderen form:
In beiden Fällen gibt es keine lifetime-parameter zur Verfügung gestellt, die über eine
argument. Dies bedeutet, dass die Lebensdauer, die
Combined
werdenparametrisierte ist auch nicht eingeschränkt durch nichts - es kann alles sein
der Anrufer es will. Dies ist unsinnig, da der Anrufer
geben die
'static
Lebensdauer und es gibt keine Möglichkeit, sich zu treffen, dassZustand.
Wie behebe ich es?
Die einfachste und empfohlene Lösung ist nicht zu versuchen zu setzen
diese Elemente in der gleichen Struktur zusammen. Indem er dies tut, Ihre
Struktur Verschachtelung wird imitieren die Lebensdauer Ihres Codes. Ort Typen
dass die eigenen Daten in einer Struktur zusammen und bieten dann Methoden, die
erlauben Sie, um Verweise oder Objekte mit verweisen, wie gebraucht.
Gibt es einen besonderen Fall, wo die lifetime-tracking ist übereifrig:
wenn Sie etwas haben, platziert auf dem heap. Dies geschieht, wenn Sie verwenden ein
Box<T>
zum Beispiel. In diesem Fall, die Struktur, die bewegtenthält einen Zeiger in den heap. Der Spitzen-Wert bleibt
stabil, aber die Adresse des Zeigers selbst bewegen wird. In der Praxis
das ist egal, da Sie immer Folgen Sie den Mauszeiger.
Den Vermietung Kiste oder die owning_ref Kiste sind
Möglichkeiten, diesem Fall, aber Sie
verlangen Sie, dass die Basis-Adresse nie bewegen. Diese Regeln mutiert
Vektoren, die kann dazu führen, eine Umverteilung und eine Bewegung des
heap-allokierten Werte.
Beispiele von Problemen gelöst, mit Vermietung:
In anderen Fällen möchten Sie vielleicht zu verschieben, um irgendeine Art von reference-counting, wie durch die Verwendung
Rc
oderArc
.Mehr Informationen
Es ist zwar theoretisch möglich, dies zu tun, so würde dies die Einführung einer großen Menge von Komplexität und den Aufwand. Jedes mal, wenn Objekt bewegt wird, würde der compiler muss code einfügen zu "fix up" die Referenz. Dies würde bedeuten, dass das kopieren einer struct ist nicht mehr eine sehr billige operation, die nur bewegt einige bits um. Es könnte sogar bedeuten, dass code wie dieser ist teuer, je nachdem, wie gut eine hypothetische optimizer wäre:
Stattdessen zwingen Sie das geschehen für jeder bewegen, der Programmierer bekommt wählen Sie Wann das passieren wird, durch die Schaffung von Methoden, die die entsprechenden Verweise nur, wenn Sie Sie nennen.
Ein Typ mit einer Referenz auf sich selbst
Es gibt einen bestimmten Fall, wo Sie kann erstellen Sie ein Typ mit einer Referenz auf sich selbst. Sie müssen so etwas wie
Option
machen es in zwei Schritten allerdings:Dies funktioniert, in gewissem Sinne, aber die Wertschöpfung ist stark eingeschränkt - es können nie verschoben werden. Vor allem, das bedeutet, es kann nicht sein, der von einer Funktion zurückzugeben oder zu übergeben-Wert, zu nichts. Eine Konstruktor-Funktion zeigt das gleiche problem mit der Lebensdauer wie oben:
Was
Pin
?Pin
, stabilisiert, Rost 1.33, hat diese in der Modul-Dokumentation:Es ist wichtig zu beachten, dass "selbstreferentielle" nicht unbedingt bedeuten, mit eine Referenz. In der Tat, die Beispiel für eine selbst-referenzielle Struktur sagt ausdrücklich (Hervorhebung von mir):
Die Möglichkeit der Verwendung eines raw-pointer für dieses Verhalten gibt es seit Rust 1.0. In der Tat, der Besitz-ref und Vermietung verwenden Sie raw-Zeiger unter der Haube.
Das einzige, was
Pin
ergänzt die Tabelle ist ein gemeinsamer Weg, um Zustand, der einem gegebenen Wert, ist garantiert nicht bewegen.Siehe auch:
sicher, es bedeutet nur, dass
Combined
besitzt dieChild
besitzt, die dieParent
. , Die möglicherweise oder möglicherweise nicht sinnvoll, je nach der tatsächlichen Typen, die Sie haben. Rückkehr Verweise auf Ihre eigenen internen Daten ist ziemlich typisch.Was ist die Lösung, um die heap-problem?
vielleicht könnte man erweitern auf Ihren Kommentar? Warum ist den gesamten Absatz sprechen über das owning_ref Kiste unzureichend?
es ist immer noch unmöglich, zu speichern Verweis und einen Wert verweisen.
Pin
ist meist ein Weg, zu wissen, die Sicherheit von ein struct mit einem selbstreferentielle Zeiger. Die Möglichkeit der Verwendung eines raw-pointer für den gleichen Zweck existiert seit Rust 1.0.InformationsquelleAutor Shepmaster
Eine etwas andere Frage, welche Ursachen sehr ähnliche compiler-Meldungen ist eine Objekt-Lebenszeit-Abhängigkeit, sondern eher als das speichern eines ausdrücklichen Verweises. Ein Beispiel dafür ist die ssh2 Bibliothek. Bei der Entwicklung etwas größer als ein test-Projekt, ist es verlockend, zu versuchen, die
Session
undChannel
erhalten, die aus dieser Sitzung neben einander in ein struct, das verbergen der Implementierungsdetails vor dem Anwender. Beachten Sie jedoch, dass dieChannel
definition hat die'sess
Lebenszeit in seiner Art annotation, währendSession
nicht.Diese verursacht ähnliche compiler-Fehlern zu Leben.
Einen Weg, es zu lösen in einer sehr einfachen Art und Weise ist zu erklären, dass die
Session
außerhalb der Anrufer, und dann kommentieren Sie den Verweis in der Struktur mit einer Lebensdauer, ähnlich wie die Antwort in dieser Rost User ' s Forum posten reden über das gleiche Problem während der Verkapselung von SFTP. Dies wird nicht sehen elegant aus und können nicht immer gelten - denn jetzt haben Sie zwei Entitäten zu behandeln, eher als eine, die Sie wollten!Stellt sich heraus, das Vermietung Kiste oder die owning_ref Kiste aus der anderen Antwort sind die Lösungen für dieses Problem zu. Wir betrachten die owning_ref, die das spezielle Objekt für genau diesen Zweck:
OwningHandle
. Um zu vermeiden, das zugrunde liegende Objekt verschieben, teilen wir es auf dem heap, der eineBox
, das gibt uns die folgende mögliche Lösung:Das Ergebnis dieses Codes ist, dass wir nicht verwenden können, die
Session
mehr, aber es ist gespeichert zusammen mit derChannel
die wir verwenden werden. Da dieOwningHandle
Objekt dereferenziert zuBox
, welche dereferenziert zuChannel
, wenn eine Aufbewahrung in einem struct, nennen wir es so. HINWEIS: Dies ist nur mein Verständnis. Ich habe den Verdacht das kann nicht richtig sein, da es scheint ganz in der Nähe Diskussion vonOwningHandle
unsafety.Ein neugierig detail ist hier, dass die
Session
logisch hat eine ähnliche Beziehung mitTcpStream
alsChannel
hatSession
ist, doch ist sein Eigentum nicht genommen wird und es gibt keine Typ-Annotationen um dies zu tun. Stattdessen ist es die Aufgabe des Benutzers, sich darum kümmern, wie die Dokumentation von handshake Methode sagt:Also mit der
TcpStream
Nutzung ist komplett bis auf den Programmierer, um sicherzustellen, die Richtigkeit des Codes. Mit derOwningHandle
, die Aufmerksamkeit auf, wo die "gefährliche Magie" passiert, ist gezeichnet mit derunsafe {}
block.Eine weitere und eine weitere high-level-Diskussion zu diesem Thema ist in diesem Rost-User - Forum-thread - und das beinhaltet ein anderes Beispiel und seine Lösung mit Hilfe der Miet-Kiste, die nicht enthalten unsafe-Blöcke.
InformationsquelleAutor
Schauen wir uns eine einfache Implementierung dieser:
Schlägt dies fehl mit der Fehlermeldung:
Vollständig zu verstehen, dieser Fehler, den Sie haben, darüber nachzudenken, wie die
die Werte sind dargestellt in den Speicher und was passiert, wenn Sie bewegen
solche Werte. Lassen Sie uns kommentieren
Combined::new
mit einigen hypothetischenSpeicher-Adressen, die anzeigen, wo die Werte befinden sich:
Was passieren sollte
child
? Wenn der Wert wurde nur verschoben wieparent
war, dann wäre es beziehen sich auf Speicher, die nicht mehr ist garantiert
haben Sie einen gültigen Wert in es. Jedem anderen Stück code gespeichert werden dürfen
Werte im Speicher Adresse 0x1000. Der Zugriff auf diesen Speicher vorausgesetzt, es war
ein integer könnte führen zu Abstürzen und/oder security-bugs, und ist einer der
die wichtigsten Kategorien der Fehler, die Rost verhindert.
Genau das ist das problem, dass Leben verhindern. Ein Leben lang ist eine
etwas von Metadaten, mit denen Sie und der compiler wissen, wie lange ein
Wert wird gültig sein aktuellen Speicherort. Das ist ein
wichtige Unterscheidung, da es ein häufiger Fehler, den Rost Neulinge machen.
Rost-Lebensdauer nicht die Zeit zwischen, wenn Sie ein Objekt
geschaffen, und wenn es zerstört!
Als eine Analogie, denken Sie an es auf diese Weise: Während das Leben einer person, Sie wird
befinden sich an vielen verschiedenen Standorten, die jeweils mit einer eindeutigen Adresse. Ein
Rost Lebenszeit beschäftigt sich mit der Adresse, die Sie befinden sich derzeit in,
nicht etwa, wenn Sie sterben in die Zukunft (auch wenn sterben auch
änderungen Ihrer Adresse). Jedes mal, wenn Sie verschieben, es ist relevant, weil Ihre
Adresse ist nicht mehr gültig.
Es ist auch wichtig zu beachten, dass die Lebensdauer nicht den code ändern; Ihre
code steuert das Leben, Ihr Leben keinen Einfluss auf den code. Die
markige Spruch "Leben sind deskriptiv, nicht präskriptiv".
Let ' s kommentieren
Combined::new
mit einigen line-Nummern, die wir verwendenmarkieren Lebensdauer:
Den konkrete Leben von
parent
ist von 1 bis 4, inklusive (die werde ichstellen
[1,4]
). Die konkrete Lebensdauer vonchild
ist[2,4]
, unddie konkrete Lebensdauer der Rückgabewert ist
[4,5]
. Es istmöglich ist das konkrete Leben, bei null anfangen - das würde
repräsentieren Sie die Lebensdauer der parameter an eine Funktion oder etwas, dass
existierte außerhalb des Blocks.
Beachten Sie, dass die Lebensdauer von
child
selbst ist[2,4]
ist, sondern dass es bezieht sichzu einen Wert mit einer Lebensdauer von
[1,4]
. Dies ist unproblematisch, solange diebezugnehmend Wert ungültig wird, bevor die genannte-Wert hat. Die
problem tritt auf, wenn wir versuchen, wieder
child
aus dem block. Dies würde"over-extend" das Leben über seine Natürliche Länge.
Diese neuen Erkenntnisse erklären die ersten beiden Beispiele. Die Dritte
benötigt man Blick auf die Umsetzung der
Parent::child
. Chancensind, es wird in etwa so Aussehen:
Diese verwendet Lebensdauer elision zu vermeiden, schreiben explizite generic
lifetime Parameter. Es ist äquivalent zu:
In beiden Fällen die Methode sagt, dass eine
Child
Strukturzurückgegeben wurde, parametrisiert mit der konkreten Lebensdauer
self
. Mit anderen Worten, dieChild
Instanz enthält eine Referenzder
Parent
erstellt wurden, und kann so nicht länger Leben als dieParent
Instanz.Dies lässt uns auch erkennen, dass etwas wirklich falsch mit unserer
Erstellung Funktion:
Obwohl Sie sind eher zu sehen, geschrieben in einer anderen form:
In beiden Fällen gibt es keine lifetime-parameter zur Verfügung gestellt, die über eine
argument. Dies bedeutet, dass die Lebensdauer, die
Combined
werdenparametrisierte ist auch nicht eingeschränkt durch nichts - es kann alles sein
der Anrufer es will. Dies ist unsinnig, da der Anrufer
geben die
'static
Lebensdauer und es gibt keine Möglichkeit, sich zu treffen, dassZustand.
Wie behebe ich es?
Die einfachste und empfohlene Lösung ist nicht zu versuchen zu setzen
diese Elemente in der gleichen Struktur zusammen. Indem er dies tut, Ihre
Struktur Verschachtelung wird imitieren die Lebensdauer Ihres Codes. Ort Typen
dass die eigenen Daten in einer Struktur zusammen und bieten dann Methoden, die
erlauben Sie, um Verweise oder Objekte mit verweisen, wie gebraucht.
Gibt es einen besonderen Fall, wo die lifetime-tracking ist übereifrig:
wenn Sie etwas haben, platziert auf dem heap. Dies geschieht, wenn Sie verwenden ein
Box<T>
zum Beispiel. In diesem Fall, die Struktur, die bewegtenthält einen Zeiger in den heap. Der Spitzen-Wert bleibt
stabil, aber die Adresse des Zeigers selbst bewegen wird. In der Praxis
das ist egal, da Sie immer Folgen Sie den Mauszeiger.
Den Vermietung Kiste oder die owning_ref Kiste sind
Möglichkeiten, diesem Fall, aber Sie
verlangen Sie, dass die Basis-Adresse nie bewegen. Diese Regeln mutiert
Vektoren, die kann dazu führen, eine Umverteilung und eine Bewegung des
heap-allokierten Werte.
Beispiele von Problemen gelöst, mit Vermietung:
In anderen Fällen möchten Sie vielleicht zu verschieben, um irgendeine Art von reference-counting, wie durch die Verwendung
Rc
oderArc
.Mehr Informationen
Es ist zwar theoretisch möglich, dies zu tun, so würde dies die Einführung einer großen Menge von Komplexität und den Aufwand. Jedes mal, wenn Objekt bewegt wird, würde der compiler muss code einfügen zu "fix up" die Referenz. Dies würde bedeuten, dass das kopieren einer struct ist nicht mehr eine sehr billige operation, die nur bewegt einige bits um. Es könnte sogar bedeuten, dass code wie dieser ist teuer, je nachdem, wie gut eine hypothetische optimizer wäre:
Stattdessen zwingen Sie das geschehen für jeder bewegen, der Programmierer bekommt wählen Sie Wann das passieren wird, durch die Schaffung von Methoden, die die entsprechenden Verweise nur, wenn Sie Sie nennen.
Ein Typ mit einer Referenz auf sich selbst
Es gibt einen bestimmten Fall, wo Sie kann erstellen Sie ein Typ mit einer Referenz auf sich selbst. Sie müssen so etwas wie
Option
machen es in zwei Schritten allerdings:Dies funktioniert, in gewissem Sinne, aber die Wertschöpfung ist stark eingeschränkt - es können nie verschoben werden. Vor allem, das bedeutet, es kann nicht sein, der von einer Funktion zurückzugeben oder zu übergeben-Wert, zu nichts. Eine Konstruktor-Funktion zeigt das gleiche problem mit der Lebensdauer wie oben:
Was
Pin
?Pin
, stabilisiert, Rost 1.33, hat diese in der Modul-Dokumentation:Es ist wichtig zu beachten, dass "selbstreferentielle" nicht unbedingt bedeuten, mit eine Referenz. In der Tat, die Beispiel für eine selbst-referenzielle Struktur sagt ausdrücklich (Hervorhebung von mir):
Die Möglichkeit der Verwendung eines raw-pointer für dieses Verhalten gibt es seit Rust 1.0. In der Tat, der Besitz-ref und Vermietung verwenden Sie raw-Zeiger unter der Haube.
Das einzige, was
Pin
ergänzt die Tabelle ist ein gemeinsamer Weg, um Zustand, der einem gegebenen Wert, ist garantiert nicht bewegen.Siehe auch:
Combined
besitzt dieChild
besitzt, die dieParent
. , Die möglicherweise oder möglicherweise nicht sinnvoll, je nach der tatsächlichen Typen, die Sie haben. Rückkehr Verweise auf Ihre eigenen internen Daten ist ziemlich typisch.owning_ref
Kiste ist eine Möglichkeit der Darstellung ist dieser Fall, aber erfordert, dass die Adresse nie verschieben", machte mich denke, es ist nicht möglich, diese in allen Situationen. Ich werde versuchen, es herauszufinden besser durch das spielen mitowning_ref
Rc<WhatAboutThis>
auscreator()
?Rc
bewegt er sich. Seit einRc
verwendet heap, Sie können stattdessen Vermietung / owning_ref.Rc
würde, dann wäre es in Ordnung. Aber ja, es sieht aus wie Sie können nicht. :-/&p
das Kind hält nicht mehr gültig. 2. Und Leben fängt solche Fehler perfekt, da&p
nur mit Lebensdauer - [2,4], die Rückkehr wird erfordern, eine längere Lebensdauer?std::pin::Pin<P>
selbstreferentielle Strukturen sind jetzt möglich. Es könnte sich lohnen, die Aktualisierung dieser Antwort mit einem kleinen Hinweis über das.Pin
ist meist ein Weg, zu wissen, die Sicherheit von ein struct mit einem selbstreferentielle Zeiger. Die Möglichkeit der Verwendung eines raw-pointer für den gleichen Zweck existiert seit Rust 1.0.Eine etwas andere Frage, welche Ursachen sehr ähnliche compiler-Meldungen ist eine Objekt-Lebenszeit-Abhängigkeit, sondern eher als das speichern eines ausdrücklichen Verweises. Ein Beispiel dafür ist die ssh2 Bibliothek. Bei der Entwicklung etwas größer als ein test-Projekt, ist es verlockend, zu versuchen, die
Session
undChannel
erhalten, die aus dieser Sitzung neben einander in ein struct, das verbergen der Implementierungsdetails vor dem Anwender. Beachten Sie jedoch, dass dieChannel
definition hat die'sess
Lebenszeit in seiner Art annotation, währendSession
nicht.Diese verursacht ähnliche compiler-Fehlern zu Leben.
Einen Weg, es zu lösen in einer sehr einfachen Art und Weise ist zu erklären, dass die
Session
außerhalb der Anrufer, und dann kommentieren Sie den Verweis in der Struktur mit einer Lebensdauer, ähnlich wie die Antwort in dieser Rost User ' s Forum posten reden über das gleiche Problem während der Verkapselung von SFTP. Dies wird nicht sehen elegant aus und können nicht immer gelten - denn jetzt haben Sie zwei Entitäten zu behandeln, eher als eine, die Sie wollten!Stellt sich heraus, das Vermietung Kiste oder die owning_ref Kiste aus der anderen Antwort sind die Lösungen für dieses Problem zu. Wir betrachten die owning_ref, die das spezielle Objekt für genau diesen Zweck:
OwningHandle
. Um zu vermeiden, das zugrunde liegende Objekt verschieben, teilen wir es auf dem heap, der eineBox
, das gibt uns die folgende mögliche Lösung:Das Ergebnis dieses Codes ist, dass wir nicht verwenden können, die
Session
mehr, aber es ist gespeichert zusammen mit derChannel
die wir verwenden werden. Da dieOwningHandle
Objekt dereferenziert zuBox
, welche dereferenziert zuChannel
, wenn eine Aufbewahrung in einem struct, nennen wir es so. HINWEIS: Dies ist nur mein Verständnis. Ich habe den Verdacht das kann nicht richtig sein, da es scheint ganz in der Nähe Diskussion vonOwningHandle
unsafety.Ein neugierig detail ist hier, dass die
Session
logisch hat eine ähnliche Beziehung mitTcpStream
alsChannel
hatSession
ist, doch ist sein Eigentum nicht genommen wird und es gibt keine Typ-Annotationen um dies zu tun. Stattdessen ist es die Aufgabe des Benutzers, sich darum kümmern, wie die Dokumentation von handshake Methode sagt:Also mit der
TcpStream
Nutzung ist komplett bis auf den Programmierer, um sicherzustellen, die Richtigkeit des Codes. Mit derOwningHandle
, die Aufmerksamkeit auf, wo die "gefährliche Magie" passiert, ist gezeichnet mit derunsafe {}
block.Eine weitere und eine weitere high-level-Diskussion zu diesem Thema ist in diesem Rost-User-Forum-thread - und das beinhaltet ein anderes Beispiel und seine Lösung mit Hilfe der Miet-Kiste, die nicht enthalten unsafe-Blöcke.