728x90
또 포인터야? 오늘도 포인터 때문에 이해안돼서 애먹었는데..?
포인터(pointer): 메모리의 주솟값을 담고 있는 변수에 대한 일반적인 개념
스마트 포인터(smart pointer): 포인터 + 추가적인 메타데이터와 능력
- C++에서 유래됨. 이해하기 어려우면 C++에서 먼저 이해하고 오자
1. Box<T>
Box<T>
- 힙에 데이터 저장
- 스택과 비교해서 힙에 저장하는것 제외하면 성능 측면에서 오버헤드 없음
사용하는 이유(이해 못함)
- 컴파일 타임에는 크기를 알 수 없는 타입이 있는데, 정확한 크기를 요구하는 컨텍스트 내에서 그 타입의 값을 사용하고 싶을 때
- 재귀적 타입을 사용하면 공간의 크기를 알기 어려움.
- Box<T>인 포인터로 대체하면 크기가 고정되므로 사용할수 있음
- 커다란 데이터를 가지고 있고 소유권을 옮기고 싶지만 그렇게 했을 때 데이터가 복사되지 않을 것을 보장하고 싶을 때
- 스택에 포인터 데이터만 복사하고 다량의 데이터는 힙에 두고 사용
- 어떤 값을 소유하고 이 값의 구체화된 타입보다는 특정 트레이트를 구현한 타입이라는 점만 신경 쓰고 싶을 때
- 트레이트 객체
예시
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
2. Deref 트레이트, 스마트 포인터를 보통참조자처럼 취급하기
Deref 트레이트
- 역참조 연산자 *(dereference operator) 동작을 커스터마이징 할 수 있음.
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y); //역참조
}
Deref coercion 역참조 강제
- 어떤 타입의 참조자를 다른 타입의 참조자로 변경
- 명시적인 참조, 역참조를 추가할 필요가 없도록 하기위해 도입됨
역참조 강제가 가변성과 상호작용하는 법
- T: Deref<Target=U>일 때 &T에서 &U로
- T: DerefMut<Target=U>일 때 &mut T에서 &mut U로
- T: Deref<Target=U>일 때 &mut T에서 &U로
3. Drop 트레이트
Drop: 메모리 정리 코드 실행
- 값이 스코프 밖으로 벗어날때마다 실행되는 코드
- 버려지는 순서는 만들어진 순서의 역순으로 진행됨
std::mem::drop
- Drop 트레이트가 실행되기 전에 먼저 정리 하고 싶은 경우 사용
- 두 번 정리하는 것을 막음
https://doc.rust-kr.org/ch15-00-smart-pointers.html
'STUDY > Rust' 카테고리의 다른 글
Rust - 20. 동시성, 병렬성 (1) | 2024.03.24 |
---|---|
Rust - 19. 스마트 포인터 (2) Rc<T>, RefCell<T>, 순환 참조 (1) | 2024.03.23 |
Rust - 17. Cargo와 Crates.io (0) | 2024.03.19 |
Rust - 16. 반복자 (0) | 2024.03.14 |
Rust - 15. 클로저 (0) | 2024.03.11 |