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>
가 불변이어도 내부의 값은 가변으로 사용 가능
불변 소유권 대여도 가능
소유권 규칙
- 여러 번 빌려도 괜찮습니다
- 한 번 빌리는 것도 괜찮습니다
- 하지만 가변과 불변이 대여는 불가능합니다
런타임 시간에 소유권이 확인되기 때문에 컴파일이 되지만 런타임 에러 발생
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();
}
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();
}