Ce face Weak
Rc::downgrade(&r) creează un Weak<T>, o referință „slabă”: nu mărește contorul de proprietari, deci nu împiedică eliberarea valorii. Pentru a folosi valoarea, apelezi upgrade(), care returnează Some(Rc) dacă valoarea încă există sau None dacă a fost eliberată.
Weak rezolvă problema ciclurilor: într-un arbore, părintele ține copiii cu Rc, iar copiii țin părintele cu Weak. Așa, când dispare arborele, totul se eliberează. Există și std::sync::Weak, perechea lui Arc, cu aceleași metode.
Ce returnează
downgrade: un Weak<T>. upgrade: Option<Rc<T>>.
Exemple
Exemplul 1: upgrade după ce valoarea a dispărut
use std::rc::Rc;
fn main() {
let sesiune = Rc::new(String::from("sesiunea Anei"));
let slaba = Rc::downgrade(&sesiune);
println!("proprietari: {}, slabe: {}", Rc::strong_count(&sesiune), Rc::weak_count(&sesiune));
println!("upgrade: {:?}", slaba.upgrade());
drop(sesiune);
println!("după drop, upgrade: {:?}", slaba.upgrade());
}
Rezultat
proprietari: 1, slabe: 1
upgrade: Some("sesiunea Anei")
după drop, upgrade: None
Exemplul 2: Arbore cu legătură spre părinte
Copilul își găsește părintele prin Weak. Contorul de proprietari al părintelui rămâne 1.
use std::cell::RefCell;
use std::rc::{Rc, Weak};
struct Nod {
nume: String,
parinte: RefCell<Weak<Nod>>,
copii: RefCell<Vec<Rc<Nod>>>,
}
fn nod(nume: &str) -> Rc<Nod> {
Rc::new(Nod {
nume: nume.to_string(),
parinte: RefCell::new(Weak::new()),
copii: RefCell::new(Vec::new()),
})
}
fn main() {
let romania = nod("România");
let iasi = nod("Iași");
*iasi.parinte.borrow_mut() = Rc::downgrade(&romania);
romania.copii.borrow_mut().push(Rc::clone(&iasi));
match iasi.parinte.borrow().upgrade() {
Some(p) => println!("{} este în {}", iasi.nume, p.nume),
None => println!("{} nu are părinte", iasi.nume),
}
println!("{} are {} copii", romania.nume, romania.copii.borrow().len());
println!("proprietari România: {}", Rc::strong_count(&romania));
}
Rezultat
Iași este în România
România are 1 copii
proprietari România: 1
Greșeli frecvente
- Păstrezi rezultatul lui
upgrade()mult timp: acelRcține valoarea în viață. Făupgradedoar cât ai nevoie de valoare. - Presupui că
upgrade()reușește mereu și scriiunwrap(): dacă proprietarii au dispărut, programul intră în panică.
Comenzi înrudite
Rc: Pointer cu numărarea referințelor: mai mulți proprietari împart aceeași valoare, eliberată când dispare ultimul.RefCell: Permite modificarea unei valori prin referință comună (&), verificând regulile de împrumut la rulare, nu la compilare.Arc: Varianta lui Rc care poate fi împărțită între fire: contorul de proprietari este actualizat atomic.mem::drop: Distruge o valoare imediat, înainte de sfârșitul blocului: eliberează memoria, închide fișierul, deblochează mutex-ul.