C.W.K.
Stream
Lesson 01 of 05 · published

Box — 힙 위의 값

~11 min · smart-pointers, box, recursive-types

Level 0Rust 호기심러
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

스마트 포인터는 포인터처럼 행동하면서 능력을 더하는 타입이야 — 소유권, 참조 카운팅, 내부 가변성. 제일 단순한 게 Box<T>: 힙에 사는 값.

Box: 힙 위의 값

Box<T> 는 자기 T 를 힙에 저장하고 스택에 그걸로의 포인터를 들어. 값을 소유하고 (Box 가 drop 될 때 값을 drop) 그 외엔 값 자체처럼 행동해. 대부분은 필요 없어 — 값은 스택에서 행복하게 살거든. Box 엔 세 특정 상황에 손 뻗어.

Box 가 필요할 때

하나: 재귀 타입, 자기 자신을 품는 트리 노드처럼 — 간접 없이는 크기가 무한해지니 Box 가 순환을 끊어. 둘: 싸게 move 하고 싶은 큰 값 (바이트가 아니라 포인터를 move). 셋: 트레잇 객체, Box<dyn Trait>, Traits 트랙에서 만난 — 다른 크기 구체 타입으로의 고정 크기 핸들.

Box 는 제일 단순한 스마트 포인터야: 소유, 힙 할당, 단일 owner. 힙 저장만 더하고 그 외엔 없어 — 평범한 값과 같은 소유권 규칙, 그냥 힙에 사는. 더 화려한 포인터 (Rc, RefCell, Arc) 가 그 위에 짓는 토대야.

재귀 타입의 정석

enum List { Cons(i32, List), Nil } 같은 타입은 컴파일 안 돼 — 영원히 중첩돼서 Rust 가 크기를 못 계산해. 재귀 필드를 Box 로 감싸 — Cons(i32, Box<List>) — 그럼 크기가 'i32 더하기 포인터' 가 돼, 유한하고 알려진. Box 가 존재하는 교과서적 이유야.

Code

재귀 타입용 Box, 그리고 평범한 힙 값용·rust
// 재귀 타입은 간접이 필요해 안 그럼 크기가 무한:
enum List {
    Cons(i32, Box<List>), // Box: 다음 노드로의 고정 크기 포인터
    Nil,
}

use List::{Cons, Nil};

fn main() {
    let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));

    // Box 는 그냥 아무 값이나 힙에 두기도 해:
    let boxed = Box::new(42);
    println!("{}", *boxed); // 값을 읽으려고 deref

    if let Cons(head, _) = list {
        println!("head: {head}");
    }
}

External links

Exercise

각 노드가 i32 랑 두 자식 서브트리를 든 재귀 이진 트리 노드 enum 을 정의해. Box 없이 컴파일 실패하는 걸 봐 (무한 크기). 자식을 Box 로 감싸고 작은 세 노드 트리를 지어. Box 가 왜 크기를 유한하게 만들어?
Hint
Box 는 뭘 가리키든 항상 포인터 크기야. 그래서 Node 가 더 많은 Node 를 품어도 Box<Node> 는 고정 크기야 — 재귀가 인라인 데이터가 아니라 포인터를 거치거든.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.