RefCell<T>
Rc<T>
의 한계
Rc
use std::rc::Rc; struct Owner { name: String, tools: Rc<Vec<Rc<Tool>>>, } struct Tool { owner: Rc<Owner>, } pub fn main() { let indo = Rc::new(Owner { name: "indo".to_string(), tools: Rc::new(vec![]), }); let pliers = Rc::new(Tool { owner: Rc::clone(&indo), }); let wrench = Rc::new(Tool { owner: indo.clone(), }); indo.tools.push(Rc::clone(&pliers)); // 🤯 indo.tools.push(Rc::clone(&wrench)); println!("Pliers owner: {}", pliers.owner.name); for tool in indo.tools.iter() { println!("Tool's owner: {:?}", tool.owner.name); } }
실행 결과
error[E0596]: cannot borrow data in an `Rc` as mutable
--> src/main.rs:24:5
|
24 | brad.tools.push(Rc::clone(&pliers)); // 🤯
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
...
use std::{cell::RefCell, rc::Rc}; struct Owner { name: String, tools: RefCell<Vec<Rc<Tool>>>, } struct Tool { owner: Rc<Owner>, } pub fn main() { let indo = Rc::from(Owner { name: "indo".to_string(), tools: RefCell::new(vec![]), }); let pliers = Rc::from(Tool { owner: Rc::clone(&indo), }); let wrench = Rc::from(Tool { owner: indo.clone(), }); indo.tools.borrow_mut().push(Rc::clone(&pliers)); indo.tools.borrow_mut().push(Rc::clone(&wrench)); println!("Pliers owner: {}", pliers.owner.name); for tool in indo.tools.borrow().iter() { println!("Tool's owner: {:?}", tool.owner.name); } }
내부 가변성(Interiror mutability)
RefCell<T>
가 불변이어도 내부의 값은 가변으로 사용 가능
#![allow(unused)] fn main() { indo.tools.borrow_mut().push(Rc::clone(&pliers)); }
불변 소유권 대여도 가능
#![allow(unused)] fn main() { indo.tools.borrow().iter() }
소유권 규칙
- 여러 번 빌려도 괜찮습니다
- 한 번 빌리는 것도 괜찮습니다
- 하지만 가변과 불변이 대여는 불가능합니다
런타임 시간에 소유권이 확인되기 때문에 컴파일이 되지만 런타임 에러 발생
use std::{cell::RefCell, rc::Rc}; struct Owner { name: String, tools: RefCell<Vec<Rc<Tool>>>, } struct Tool { owner: Rc<Owner>, } pub fn main() { let indo = Rc::from(Owner { name: "indo".to_string(), tools: RefCell::new(vec![]), }); let pliers = Rc::from(Tool { owner: Rc::clone(&indo), }); let wrench = Rc::from(Tool { owner: indo.clone(), }); let mut borrow_mut_tools1 = indo.tools.borrow_mut(); let mut borrow_mut_tools2 = indo.tools.borrow_mut(); // 🤯 borrow_mut_tools1.push(Rc::clone(&pliers)); borrow_mut_tools2.push(Rc::clone(&wrench)); println!("Pliers owner: {}", pliers.owner.name); for tool in indo.tools.borrow().iter() { println!("Tool's owner: {:?}", tool.owner.name); } }
실행 결과
thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:25:44
Rc<RefCell<T>>
RefCell<T>
를 사용하는 일반적인 방법은 Rc<T>
와 함께 사용하는 것입니다. Rc<T>
를 사용하면 일부 데이터의 소유자를 여러 명 가질 수 있지만, 해당 데이터에 대한 불변 액세스 권한만 부여한다는 점을 기억하세요. RefCell<T>
를 보유한 Rc<T>
가 있다면, 여러 소유자를 가질 수 있고 변경할 수 있는 값을 얻을 수 있습니다!
요약하자면, Rc는 공유 소유권을 제공합니다. 내부 값에는 여러 소유자가 있으며, 참조 카운팅은 적어도 한 명의 소유자가 데이터를 계속 보유하고 있는 한 데이터가 계속 유지되도록 합니다. 이는 데이터 소유자가 명확하지 않은 경우에 유용합니다. RefCell은 내부 가변성을 제공합니다. 즉, 런타임에 내부 값을 동적으로 빌릴 수 있고 공유 참조를 통해서도 수정할 수 있습니다. Rc<RefCell<...>> 조합은 소유자가 여러 명인 값을 소유자 중 한 명이 가변적으로 빌릴 수 있는 두 가지의 조합을 제공합니다.
언제 무엇을
Box<T> | Rc<T> | RefCell<T> | |
---|---|---|---|
소유권 | 한 개 | 한 개를 공유 | 한 개 |
소유권 확인 시점 | 불변/가변 소유권을 컴파일 타임에 확인 | 불변 소유권을 컴파일 타임에 확인 | 불변/가변 소유권을 런타임에 확인 |
특징 | 스코프를 벗어나면 레퍼런스도 모두 삭제 | 레퍼런스가 존재한다면 스코프를 벗어나도 값이 유지됨 | RefCell<T> 가 불변이어도 내부의 값은 가변으로 사용 가능 |
RefCell
는 멀티스레드 코드에서는 작동하지 않는다는 점에 유의하세요! Mutex 는 스레드에 안전한 RefCell<T의 버전이며, Mutex<T에 대해서는 나중에 설명하겠습니다.
Quiz
use std::fmt::Display; use std::vec::Vec; #[derive(Debug)] struct Node<T> { data: T, children: Vec<Node<T>>, } impl<T: Display> Node<T> { fn new(data: T) -> Node<T> { Node { data, children: Vec::new(), } } fn depth_first(&self) { println!("{}", self.data); for child in self.children.iter() { child.depth_first(); } } } fn main() { let mut a = Node::new('A'); let mut b = Node::new('B'); let c = Node::new('C'); let d = Node::new('D'); b.children.push(d); a.children.push(b); a.children.push(c); a.depth_first(); }
#![allow(unused)] fn main() { fn add_child(&mut self, child: Wrapper<Node<T>>) { self.children.push(child); } }
fn main() { let a = wrap(Node::new('A')); let b = wrap(Node::new('B')); let c = wrap(Node::new('C')); let d = wrap(Node::new('D')); a.borrow_mut().add_child(Rc::clone(&b)); a.borrow_mut().add_child(Rc::clone(&c)); b.borrow_mut().add_child(Rc::clone(&d)); a.borrow_mut().depth_first(); }
정답
use std::cell::RefCell; use std::fmt::Display; use std::rc::Rc; use std::vec::Vec; type Wrapper<T> = Rc<RefCell<T>>; fn wrap<T>(data: T) -> Wrapper<T> { Rc::new(RefCell::new(data)) } #[derive(Debug)] struct Node<T> { data: T, children: Vec<Wrapper<Node<T>>>, } impl<T: Display> Node<T> { fn add_child(&mut self, child: Wrapper<Node<T>>) { self.children.push(child); } fn new(data: T) -> Node<T> { Node { data, children: Vec::new(), } } fn depth_first(&self) { println!("node {}", self.data); for child in self.children.iter() { child.borrow().depth_first(); } } } fn main() { let a = wrap(Node::new('A')); let b = wrap(Node::new('B')); let c = wrap(Node::new('C')); let d = wrap(Node::new('D')); a.borrow_mut().add_child(Rc::clone(&b)); a.borrow_mut().add_child(Rc::clone(&c)); b.borrow_mut().add_child(Rc::clone(&d)); a.borrow_mut().depth_first(); }