Rust의 스마트 포인터는 메모리 관리와 자원 관리를 자동화하는 데 사용됩니다. 스마트 포인터는 일반 포인터와 달리 추가적인 메타데이터와 기능을 제공합니다. Rust의 주요 스마트 포인터에는 Box<T>, Rc<T>, RefCell<T> 등이 있습니다.
Box<T>는 힙에 데이터를 저장하고, 스택에는 힙 데이터에 대한 포인터를 저장합니다. 주로 크기가 큰 데이터를 힙에 저장하거나, 재귀적인 데이터 구조를 정의할 때 사용됩니다.
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
위 예제에서 Box::new를 사용하여 힙에 정수 5를 저장하고, b는 힙 데이터에 대한 포인터를 가집니다.
Rc<T>는 참조 카운팅(reference counting) 스마트 포인터로, 여러 소유자가 동일한 데이터를 가리킬 수 있게 합니다. 주로 단일 스레드 환경에서 사용됩니다.
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = Rc::clone(&a);
let c = Rc::clone(&a);
println!("a = {}, b = {}, c = {}", a, b, c);
println!("Reference count: {}", Rc::strong_count(&a));
}
위 예제에서 Rc::new를 사용하여 정수 5를 참조 카운팅 스마트 포인터로 감싸고, Rc::clone을 사용하여 여러 소유자가 동일한 데이터를 가리키게 합니다. Rc::strong_count를 사용하여 참조 카운트를 확인할 수 있습니다.
RefCell<T>는 런타임에 가변성을 제공하는 스마트 포인터로, 불변 참조와 가변 참조를 런타임에 검사합니다. 주로 단일 스레드 환경에서 내부 가변성을 허용할 때 사용됩니다.
use std::cell::RefCell;
fn main() {
let x = RefCell::new(5);
{
let mut y = x.borrow_mut();
*y += 1;
}
println!("x = {}", x.borrow());
}
위 예제에서 RefCell::new를 사용하여 정수 5를 감싸고, borrow_mut을 사용하여 가변 참조를 얻어 값을 변경합니다. borrow를 사용하여 불변 참조를 얻어 값을 읽습니다.
스마트 포인터를 조합하여 복잡한 데이터 구조를 만들 수 있습니다. 예를 들어, Rc<T>와 RefCell<T>를 조합하여 여러 소유자가 가변 데이터를 공유할 수 있습니다.
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
next: Option<Rc<RefCell<Node>>>,
}
fn main() {
let node1 = Rc::new(RefCell::new(Node { value: 1, next: None }));
let node2 = Rc::new(RefCell::new(Node { value: 2, next: None }));
node1.borrow_mut().next = Some(Rc::clone(&node2));
node2.borrow_mut().next = Some(Rc::clone(&node1));
println!("Node 1: {:?}", node1);
println!("Node 2: {:?}", node2);
}
위 예제에서 Node 구조체는 Rc<RefCell<Node>>를 사용하여 가변 데이터를 여러 소유자가 공유할 수 있게 합니다. node1과 node2는 서로를 가리키는 순환 참조를 가집니다.
Box
enum List {
Cons(i32, Box<List>),
Nil,
}Deref 트레잇
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}Drop 트레잇
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}Rc
use std::rc::Rc;
let a = Rc::new(List::Cons(5, Rc::new(List::Nil)));
let b = List::Cons(3, Rc::clone(&a));
let c = List::Cons(4, Rc::clone(&a));RefCell와 내부 가변성
use std::cell::RefCell;
struct MockMessenger {
sent_messages: RefCell<Vec<String>>,
}
impl MockMessenger {
fn send(&self, message: &str) {
self.sent_messages.borrow_mut().push(String::from(message));
}
}참조: https://doc.rust-lang.org/book/ch15-00-smart-pointers.html