Ich habe einen Code wie diesen:
%Vor%Es ist wirklich wichtig, dass ich beide dieser Operationen eventuell mache, aber oft vergesse ich, die zweite nach der ersten zu machen. Es verursacht viele Bugs und ich frage mich, ob es einen idiomatischen Rust-Weg gibt, um dieses Problem zu vermeiden. Gibt es eine Möglichkeit, den Rost-Compiler dazu zu bringen, mich wissen zu lassen, wenn ich es vergesse?
Meine Idee war, vielleicht so etwas zu haben:
%Vor%Gibt es einen besseren Weg, dies zu erreichen?
Eine weitere Idee besteht darin, Drop
und panic!
zu implementieren, wenn die Struktur gelöscht wird, ohne diese Methode aufgerufen zu haben. Dies ist jedoch nicht so gut, da es sich um eine Laufzeitprüfung handelt und das höchst unerwünscht ist.
Bearbeiten: Ich habe festgestellt, dass mein Beispiel vielleicht zu einfach war. Die involvierte Logik kann ziemlich komplex werden. Zum Beispiel haben wir so etwas:
%Vor%Beachten Sie, dass die Vorgänge nicht in einer netten, ordnungsgemäß verschachtelten Reihenfolge ausgeführt werden. Wichtig ist nur, dass die umgekehrte Operation immer danach aufgerufen wird. Die Reihenfolge muss manchmal auf eine bestimmte Weise angegeben werden, damit der Code wie erwartet funktioniert.
Wir können sogar so etwas haben:
%Vor% Sie können Phantom-Typen verwenden, um zusätzliche Informationen mitzuführen, die für die Typprüfung verwendet werden können. Eine Einschränkung ist, dass move_left_by
und move_right_by
ein neues Objekt im Besitz zurückgeben müssen, weil sie den Typ ändern müssen, aber das ist oft kein Problem.
Außerdem wird der Compiler sich beschweren, wenn Sie die Typen in Ihrer Struktur nicht verwenden, also müssen Sie Felder hinzufügen, die sie verwenden. Rust's std
liefert PhantomData
für diesen Zweck. Werte dieses Typs haben keine Laufzeitkosten.
Es kann ein wenig unhandlich sein, aber Ihre Einschränkung könnte wie folgt codiert werden:
%Vor%Sie können es wie folgt verwenden:
%Vor%Und wenn Sie eine der erforderlichen Methoden vermissen,
%Vor%Dann erhalten Sie einen Kompilierfehler:
%Vor% Ich glaube nicht, dass #[must_use]
in diesem Fall wirklich das ist, was Sie wollen. Hier sind zwei verschiedene Ansätze zur Lösung Ihres Problems. Der erste Schritt besteht darin, das, was Sie bei einem Abschluss machen müssen, abzuschließen und die direkten Aufrufe wegzuspalten:
Der zweite Ansatz besteht darin, einen Wrappertyp zu erstellen, der die Funktion aufruft, wenn sie gelöscht wird (ähnlich wie Mutex::lock
eine MutexGuard
erzeugt, die die Mutex
freigibt, wenn sie gelöscht wird):
Ich habe nur die anfängliche Beschreibung angeschaut und wahrscheinlich die Details in der Konversation verpasst, aber eine Möglichkeit, die Aktionen zu erzwingen, besteht darin, das ursprüngliche Objekt zu konsumieren (nach rechts zu gehen) und es durch eines zu ersetzen, das Sie zwingt um sich um denselben Betrag nach links zu bewegen, bevor Sie tun können, was Sie tun wollten, um die Aufgabe zu beenden.
Der neue Typ kann verbieten / erfordern, dass verschiedene Anrufe getätigt werden, bevor ein fertiger Zustand erreicht wird. Zum Beispiel (ungetestet):
%Vor% An diesem Punkt kann sich foo
nicht mehr richtig bewegen, da es von MustGoLeft
nicht erlaubt ist, aber es kann sich nach links bewegen oder die Box öffnen. Wenn es sich weit genug nach links bewegt, kehrt es wieder in den Zustand CanGoRight
zurück. Aber wenn es die Box öffnet, dann gelten völlig neue Regeln. So oder so müssen Sie mit beiden Möglichkeiten umgehen.
Es wird wahrscheinlich einige Überschneidungen zwischen den Staaten geben, aber sollte leicht genug sein, um zu refaktorieren. Das Hinzufügen eines benutzerdefinierten Merkmals könnte helfen.
Am Ende hört es sich so an, als würdest du eine Art Staatsmaschine bauen. Vielleicht wird Ссылка von Nutzen sein.
Tags und Links rust