Ich habe eine Struktur, die innere Veränderlichkeit hat.Wie kann ich einen Verweis auf etwas in einer RefCell zurückgeben, ohne die Kapselung zu unterbrechen?
use std::cell::RefCell;
struct MutableInterior {
hideMe: i32,
vec: Vec<i32>,
}
struct Foo {
//although not used in this particular snippet,
//the motivating problem uses interior mutability
//via RefCell.
interior: RefCell<MutableInterior>,
}
impl Foo {
pub fn getItems(&self) -> &Vec<i32> {
&self.interior.borrow().vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Vec::new(),
hideMe: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.getItems();
}
Erzeugt den Fehler:
error: borrowed value does not live long enough
--> src/main.rs:16:10
|
16 | &self.interior.borrow().vec
| ^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
17 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 15:40...
--> src/main.rs:15:41
|
15 | pub fn getItems(&self) -> &Vec<i32> {
| _________________________________________^ starting here...
16 | | &self.interior.borrow().vec
17 | | }
| |_____^ ...ending here
Das Problem ist, dass ich nicht vec
entlehnt gibt eine Funktion auf Foo
, die eine haben kann, weil das geliehene vec
nur gültig für die gesamte Lebensdauer des Ref
ist , aber die Ref
geht sofort aus dem Anwendungsbereich.
ich denke, die Ref
because dableiben müssen:
RefCell uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCells are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell borrows are dynamic it is possible to attempt to borrow a value that is already mutably borrowed; when this happens it results in task panic.
Jetzt habe ich stattdessen eine Funktion wie diese schreiben könnte, die den gesamten Innenraum zurückgibt:
pub fn getMutableInterior(&self) -> std::cell::Ref<MutableInterior>;
jedoch möglicherweise diese aussetzt Felder (MutableInterior.hideMe
in Dieses Beispiel), die wirklich private Implementierungsdetails zu Foo
sind.
Idealerweise möchte ich nur die vec
selbst, möglicherweise mit einer Wache, um das dynamische Ausleihen Verhalten zu implementieren. Dann müssen sich Anrufer nicht über hideMe
informieren.
Ist dies der einzige/idiomatische Weg, dies zu tun? Scheint wie ein bisschen Ärger ... Obwohl ich vermute, anstelle einer getItems() -Methode, könnten Sie die Interna in einem Block direkt ausleihen, wo es dann außerhalb des Geltungsbereichs (oder etwas ...) gehen würde – norcalli
@Norcalli Im spezifischen Im Fall von 'RefCell' muss das Objekt benachrichtigt werden, wenn die Referenz den Gültigkeitsbereich verlässt (dies tut der Destruktor von' Ref'). Hier müssen wir dieses Verhalten beibehalten (der Fehler des OP war darauf zurückzuführen, dass die "Ref" -Instanz zu früh fallen gelassen wurde) und sie somit einkapseln. – Levans