Viele Bibliotheken ermöglichen es Ihnen, einen Typ zu definieren, der einen gegebenen trait
implementiert, der als Callback-Handler verwendet werden soll. Dazu müssen Sie alle Daten, die Sie zum Behandeln des Ereignisses benötigen, in einem einzigen Datentyp zusammenfassen, was die Ausleihe erschwert.Was ist der schnellste idiomatische Weg, um mehrere Strukturfelder gleichzeitig zu mutieren?
Zum Beispiel mio
können Sie implementieren Handler
und stellen Sie Ihre Struktur, wenn Sie run the EventLoop
. Betrachten wir ein Beispiel mit diesen trivialisiert Datentypen:
struct A {
pub b: Option<B>
};
struct B;
struct MyHandlerType {
pub map: BTreeMap<Token, A>,
pub pool: Pool<B>
}
Der Handler hat eine Karte von Token
auf Elemente des Typs A
. Jeder Artikel des Typs A
kann oder darf nicht bereits einen zugeordneten Wert vom Typ B
haben. Im Handler möchten Sie den A
Wert für eine gegebene Token
nachschlagen und, wenn es nicht bereits einen B
Wert hat, einen aus der Handler Pool<B>
holen.
impl Handler for MyHandlerType {
fn ready(&mut self, event_loop: &mut EventLoop<MyHandlerType>,
token: Token, events: EventSet) {
let a : &mut A = self.map.get_mut(token).unwrap();
let b : B = a.b.take().or_else(|| self.pool.new()).unwrap();
// Continue working with `a` and `b`
// ...
}
}
In dieser Anordnung, auch wenn es intuitiv möglich ist, zu sehen, dass self.map
und self.pool
getrennte Einheiten sind, klagt der borrow checker, dass self
bereits ausgeliehen (via self.map
), wenn wir self.pool
Zugang zu gehen.
Ein möglicher Ansatz dazu wäre, jedes Feld in MyHandlerType
in Option<>
zu wickeln. Dann wird bei Beginn des Methodenaufrufes take()
diese Werte aus self
und sie am Ende des Gesprächs wieder her:
struct MyHandlerType {
// Wrap these fields in `Option`
pub map: Option<BTreeMap<Token, A>>,
pub pool: Option<Pool<B>>
}
// ...
fn ready(&mut self, event_loop: &mut EventLoop<MyHandlerType>,
token: Token, events: EventSet) {
// Move these values out of `self`
let map = self.map.take().unwrap();
let pool = self.pool.take().unwrap();
let a : &mut A = self.map.get_mut(token).unwrap();
let b : B = a.b.take().or_else(|| self.pool.new()).unwrap();
// Continue working with `a` and `b`
// ...
// Restore these values to `self`
self.map = Some(map);
self.pool = Some(pool);
}
Das funktioniert fühlt sich aber etwas Kluges-y. Es führt auch den Overhead des Verschiebens von Werten in und aus self
für jeden Methodenaufruf ein.
Was ist der beste Weg, dies zu tun?
!!! Vielen Dank! Ich wusste über Destrukturierung Bescheid, wusste aber nicht, dass man damit gleichzeitig veränderbare Referenzen erhalten könnte. Das war eine große Hilfe! – zslayton