TL;DR

  • ๊ธฐ๋ณธ ํƒ€์ž…์˜ ์ €์žฅ ๊ตฌ์กฐ์—์„œ ์ด์–ด์ง€๋Š” RcยทRefCell์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๊ณ„
  • ๊ณต์œ  ์†Œ์œ ๊ถŒ์„ ๊ด€๋ฆฌํ•˜๋Š” Rc์™€ ๋‚ด๋ถ€ ๊ฐ’ ์ ‘๊ทผ์„ ๊ด€๋ฆฌํ•˜๋Š” RefCell์˜ ๊ตฌ๋ถ„
  • RcยทRefCell ์กฐํ•ฉ๊ณผ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์— ๋”ฐ๋ฅธ ํ• ๋‹นยท์ฐธ์กฐ ์ˆ˜ยทborrow ์ƒํƒœ ๋ณ€ํ™”

AI-assisted


1. ๊ธฐ๋ณธ ํƒ€์ž…์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ

Rust์—์„œ๋Š” ownership๊ณผ borrowing ๊ทœ์น™์œผ๋กœ ๊ฐ’์˜ ์ˆ˜๋ช…๊ณผ ์ ‘๊ทผ์„ ๊ด€๋ฆฌํ•œ๋‹ค. &Tยท&mut T๋กœ ๊ฐ’์„ ๋นŒ๋ ค๋„ ์†Œ์œ ๊ถŒ์€ ๋„˜์–ด์˜ค์ง€ ์•Š์œผ๋ฏ€๋กœ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ์—๋Š” ์›๋ณธ ๊ฐ’์„ ์œ ์ง€ํ•  ์†Œ์œ ์ž๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์—ฌ๋Ÿฌ ๊ณณ์ด ๊ฐ™์€ ๊ฐ’์„ ๊ฐ์ž ํ•„์š”ํ•œ ๋™์•ˆ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๊ณต์œ  ์†Œ์œ ๊ถŒ์ด ํ•„์š”ํ•˜๋‹ค. Rc ๊ฐ™์€ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋Š” ์ฐธ์กฐ ์ˆ˜๋ฅผ ์ถ”์ ํ•ด ๋งˆ์ง€๋ง‰ ์†Œ์œ ์ž๊ฐ€ ๋†“์„ ๋•Œ๊นŒ์ง€ ๊ฐ’์„ ์œ ์ง€ํ•œ๋‹ค. ๊ณต์œ  ์ฐธ์กฐ๋กœ ๋‚ด๋ถ€ ๊ฐ’์„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค๋ฉด RefCell๋กœ ์ฝ๊ธฐยท์“ฐ๊ธฐ ์ ‘๊ทผ์„ ๊ด€๋ฆฌํ•œ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” single thread์˜ RcยทRefCell๊ณผ ๋‘ ํƒ€์ž…์˜ ์กฐํ•ฉ์„ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ์™€ ํ•จ๊ป˜ ์‚ดํŽด๋ณธ๋‹ค. ๋ณ€์ˆ˜์— ๋‹ด๊ธด ๊ฐ’๊ณผ ๊ทธ ๊ฐ’์ด ์†Œ์œ ํ•˜๊ฑฐ๋‚˜ ๋นŒ๋ฆฐ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋ฉด cloneยทborrow๊ฐ€ ๋ฌด์—‡์„ ๋ฐ”๊พธ๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค. ๋จผ์ € ์ •์ˆ˜ยท๋ฐฐ์—ดยทstruct์™€ StringยทVecยทBox์˜ ์ €์žฅ ๊ตฌ์กฐ๋ถ€ํ„ฐ ํ™•์ธํ•œ๋‹ค.

๋„์‹์˜ ๊ธฐ์ค€: ์ €์žฅ ๊ณต๊ฐ„๊ณผ ํ™”์‚ดํ‘œ์˜ ์˜๋ฏธ

  • Local variable: ํ•จ์ˆ˜ ์•ˆ์˜ ๊ฐ’์€ ๋„์‹์—์„œ stack์— ๋‘”๋‹ค. ์‹ค์ œ compiler๋Š” register๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ €์žฅ์„ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.
  • inline storage1: ์›์†Œ๋‚˜ ํ•„๋“œ๊ฐ€ ๋ฐ”๊นฅ ๊ฐ’์˜ ๊ณต๊ฐ„ ์•ˆ์— ํฌํ•จ๋œ๋‹ค. ๋ฐ”๊นฅ ๊ฐ’์ด heap์— ์žˆ์œผ๋ฉด ๊ทธ ํ•„๋“œ๋„ ๊ทธ ์•ˆ์— ์žˆ๋‹ค.
  • ์ฃผ์†Œ ๊ด€๊ณ„: ํ™”์‚ดํ‘œ๋Š” ํฌ์ธํ„ฐ๋‚˜ ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์†Œ์œ ยทborrowยทWeak๋Š” ๋ผ๋ฒจ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค.
  • ์ƒํƒœ ๋ณ€ํ™”: clone, drop, guard ์ƒ์„ฑยท๋ฐ˜๋‚ฉ ์ „ํ›„์˜ ๋‹จ๊ณ„ ๊ทธ๋ฆผ์€ ์‹œ๊ฐ„ ์ˆœ์„œ๋‹ค. ๋‹จ๊ณ„ ๋ฐ•์Šค๋งˆ๋‹ค ์ƒˆ ํ• ๋‹น์ด ์ƒ๊ธด๋‹ค๋Š” ๋œป์œผ๋กœ ์ฝ์ง€ ์•Š๋Š”๋‹ค.

๋„์‹์€ Rust ํƒ€์ž… ๋ฐฐ์น˜์˜ ํ•„๋“œ ์ˆœ์„œยทpaddingยท์ฃผ์†Œ๋ฅผ ์žฌํ˜„ํ•˜๋Š” ๊ทธ๋ฆผ์ด ์•„๋‹ˆ๋‹ค. Rc๋Š” strong count๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ํ‘œ์‹œํ•˜๊ณ  weak count์˜ ๋‚ด๋ถ€ ํ‘œํ˜„์€ ์ƒ๋žตํ•œ๋‹ค. StringยทVec ์˜ˆ์ œ๋Š” ๋น„์–ด ์žˆ์ง€ ์•Š์€ ๋ฒ„ํผ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์‹คํ–‰ ์˜ˆ์ œ๋Š” ๊ฐ๊ฐ ๋…๋ฆฝ๋œ main ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค. ์˜ˆ์ œ์˜ ๋„์‹์€ ์ฝ”๋“œ ์ฃผ์„์ด๋‚˜ ๋ณธ๋ฌธ์—์„œ ์ง€์ •ํ•œ ์‹œ์ ์˜ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

1.1 Stack์˜ ๊ฐ’๊ณผ ์ฐธ์กฐ

์ •์ˆ˜ยท๋ฐฐ์—ดยทstruct๋Š” ์ž์‹ ์˜ ๊ณต๊ฐ„ ์•ˆ์— ๊ฐ’์„ ๋‹ด๋Š”๋‹ค. ์ฐธ์กฐ๋Š” ๊ธฐ์กด ๊ฐ’์— ์ ‘๊ทผํ•  ์ฃผ์†Œ๋ฅผ ๋‹ด๊ณ  slice ์ฐธ์กฐ๋Š” ์‹œ์ž‘ ํฌ์ธํ„ฐ์™€ ๊ธธ์ด๋ฅผ ํ•จ๊ป˜ ๋‹ด๋Š”๋‹ค.

struct Point {
    x: i32,
    y: i32,
}
 
fn main() {
    let number: i32 = 10;
    let array = [10, 20, 30];
    let point = Point { x: 10, y: 20 };
    let read: &i32 = &number;
    let part: &[i32] = &array[1..];
    // ๋„์‹ ์‹œ์ : ๋‹ค์„ฏ ๋ณ€์ˆ˜๊ฐ€ ๋ชจ๋‘ ์„ ์–ธ๋œ ๋’ค
 
    assert_eq!(*read, 10);
    assert_eq!(part, &[20, 30]);
    assert_eq!(point.x + point.y, 30);
}
flowchart TB
    subgraph BASIC_STACK["Stack"]
        B_NUMBER["number: i32 = 10"]
        B_READ["read: &i32"]
        B_ARRAY["<table style='border-collapse:collapse;table-layout:fixed;width:210px'><tr><td colspan='3' style='border:none;padding:0 0 6px'>array: [i32; 3]</td></tr><tr><td style='border:1px solid currentColor;padding:8px 0'>10</td><td style='border:1px solid currentColor;padding:8px 0'>20</td><td style='border:1px solid currentColor;padding:8px 0'>30</td></tr><tr><td>[0]</td><td>[1]</td><td>[2]</td></tr></table>"]
        B_POINT["point: Point / x: 10 / y: 20"]
        B_PART["part: ํฌ์ธํ„ฐ์™€ ๊ธธ์ด 2"]
    end
    B_READ -->|number๋ฅผ ๋นŒ๋ฆผ| B_NUMBER
    B_PART -->|array 1๋ฒˆ๋ถ€ํ„ฐ ๋‘ ์›์†Œ๋ฅผ ๋นŒ๋ฆผ| B_ARRAY
  • ๋ฐฐ์—ด์˜ ์„ธ ์›์†Œ๋Š” ์—ฐ์†ํ•ด์„œ ๋†“์ธ๋‹ค. point์˜ ๋‘ ํ•„๋“œ๋„ point ์ž์‹ ์˜ ๊ณต๊ฐ„ ์•ˆ์— ํฌํ•จ๋œ๋‹ค.
  • read์™€ part๋Š” ๊ธฐ์กด ๊ฐ’์„ ๋นŒ๋ฆฐ๋‹ค. ์ด ์ฝ”๋“œ์—๋Š” ๋ณ„๋„ heap ํ• ๋‹น์ด ์—†๋‹ค.
  • &mut i32๋„ ๊ธฐ์กด ์ˆซ์ž๋ฅผ ๊ฐ€๋ฆฌํ‚ค์ง€๋งŒ ๊ทธ ์ˆซ์ž๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฐธ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์ˆซ์ž์˜ ๋ณต์‚ฌ๋ณธ์ด๋‚˜ heap ํ• ๋‹น์ด ์ƒ๊ธฐ์ง€๋Š” ์•Š๋Š”๋‹ค.

1.2 Stack์˜ ํฌ์ธํ„ฐ์™€ Heap์˜ ๋ฐ์ดํ„ฐ

String๊ณผ Vec<T>๋Š” ํฌ์ธํ„ฐยท๊ธธ์ดยทcapacity๋ฅผ ๋‹ด๋Š” ๊ด€๋ฆฌ ๊ฐ’์ด๋‹ค. ๋ฌธ์ž์—ด ๋ฐ”์ดํŠธ์™€ Vec ์›์†Œ๋Š” ๋ณ„๋„ heap ๋ฒ„ํผ์— ์žˆ๋‹ค. Box<T>๋Š” heap์— ๋‘” T๋ฅผ ์†Œ์œ ํ•˜๋Š” ํฌ์ธํ„ฐ๋‹ค.

fn main() {
    let text = String::from("hi");
    let values = vec![10, 20, 30];
    let boxed = Box::new(10);
    let text_view: &str = text.as_str();
    let values_view: &[i32] = values.as_slice();
    // ๋„์‹ ์‹œ์ : ๋‹ค์„ฏ ๋ณ€์ˆ˜๊ฐ€ ๋ชจ๋‘ ์„ ์–ธ๋œ ๋’ค
 
    assert_eq!(text_view, "hi");
    assert_eq!(values_view, &[10, 20, 30]);
    assert_eq!(*boxed, 10);
}
flowchart TB
    subgraph BUFFER_STACK["Stack"]
        S_TEXT["text: ํฌ์ธํ„ฐ, ๊ธธ์ด 2, capacity"]
        S_VALUES["values: ํฌ์ธํ„ฐ, ๊ธธ์ด 3, capacity"]
        S_BOX["boxed: Box ํฌ์ธํ„ฐ"]
        S_TEXT_VIEW["text_view: ํฌ์ธํ„ฐ, ๊ธธ์ด 2"]
        S_VALUES_VIEW["values_view: ํฌ์ธํ„ฐ, ๊ธธ์ด 3"]
    end
    subgraph BUFFER_HEAP["Heap์˜ ๋ณ„๋„ ํ• ๋‹น"]
        H_TEXT["UTF-8 ๋ฒ„ํผ: hi"]
        H_VALUES["<table style='border-collapse:collapse;table-layout:fixed;width:210px'><tr><td colspan='3' style='border:none;padding:0 0 6px'>Vec ์›์†Œ ๋ฒ„ํผ</td></tr><tr><td style='border:1px solid currentColor;padding:8px 0'>10</td><td style='border:1px solid currentColor;padding:8px 0'>20</td><td style='border:1px solid currentColor;padding:8px 0'>30</td></tr></table>"]
        H_NUMBER["i32 ๊ฐ’: 10"]
    end
    S_TEXT -->|๋ฒ„ํผ ์†Œ์œ | H_TEXT
    S_VALUES -->|๋ฒ„ํผ ์†Œ์œ | H_VALUES
    S_BOX -->|๋‚ด๋ถ€ ๊ฐ’ ์†Œ์œ | H_NUMBER
    S_TEXT_VIEW -->|๋ฐ”์ดํŠธ๋ฅผ ๋นŒ๋ฆผ| H_TEXT
    S_VALUES_VIEW -->|์›์†Œ๋ฅผ ๋นŒ๋ฆผ| H_VALUES
  • text_viewยทvalues_view๋Š” heap ๋ฒ„ํผ๋ฅผ ๋นŒ๋ฆฐ๋‹ค. StringยทVec ๊ด€๋ฆฌ ๊ฐ’ ์ž์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” &Stringยท&Vec<i32>์™€ ๋Œ€์ƒ์ด ๋‹ค๋ฅด๋‹ค.
  • push_strยทpush๋Š” ๋ฒ„ํผ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  capacity๊ฐ€ ๋ถ€์กฑํ•˜๋ฉด ์žฌํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ์กด slice๋ฅผ ์ดํ›„์—๋„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๊ทธ ์‚ฌ์ด์— Vec๋ฅผ ๊ฐ€๋ณ€ borrowํ•˜๋Š” push๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค.
  • Box<String>์ด๋ฉด String ๊ด€๋ฆฌ ๊ฐ’์ด Box์˜ heap ํ• ๋‹น ์•ˆ์— ๋“ค์–ด๊ฐ€๊ณ  ๋ฌธ์ž์—ด ๋ฒ„ํผ๋Š” ๋ณ„๋„ ํ• ๋‹น์œผ๋กœ ๋‚จ๋Š”๋‹ค. ๊ด€๋ฆฌ ๊ฐ’์˜ ์œ„์น˜์™€ ๋ฒ„ํผ์˜ ์œ„์น˜๋ฅผ ๋‚˜๋ˆ„์–ด ์ฝ๋Š”๋‹ค.

Deref coercion: ๊ธฐ๋Œ€ํ•˜๋Š” ์ฐธ์กฐ ํƒ€์ž…์œผ๋กœ์˜ ์ž๋™ ๋ณ€ํ™˜

&i32๊ฐ€ ํ•„์š”ํ•œ ์ž๋ฆฌ์—์„œ๋Š” &Box<i32>๋ฅผ ๋‚ด๋ถ€ ๊ฐ’์˜ &i32๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์ด deref coercion์ด๋‹ค.

fn main() {
    let boxed = Box::new(10);
    let borrowed: &i32 = &*boxed; // ๋‚ด๋ถ€ ๊ฐ’์„ ๋ช…์‹œ์ ์œผ๋กœ ๋นŒ๋ฆผ (clippy warning: explicit_auto_deref)
    let borrowed2: &i32 = &boxed; // ๊ธฐ๋Œ€ ํƒ€์ž…์ด &i32์ด๋ฏ€๋กœ ์ž๋™ ๋ณ€ํ™˜
 
    println!("{borrowed}");  // 10
    println!("{borrowed2}"); // 10
}

๋‘ ์ฐธ์กฐ๋Š” heap์— ์žˆ๋Š” ๊ฐ™์€ i32๋ฅผ ๋นŒ๋ฆฐ๋‹ค. &i32๋ผ๋Š” ๊ธฐ๋Œ€ ํƒ€์ž…์ด ์žˆ๋Š” ์œ„ ์˜ˆ์ œ์—์„œ &*boxed๋ฅผ ์“ฐ๋ฉด Clippy์˜ explicit_auto_deref ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ํƒ€์ž… ์ฃผ์„ ์—†์ด let borrowed2 = &boxed;๋กœ ์“ฐ๋ฉด borrowed2๋Š” &Box<i32>๋กœ ์ถ”๋ก ๋œ๋‹ค.

ํ‘œํ˜„๊ธฐ์กด ๊ฐ’๊ณผ ๋ณ€์ˆ˜์˜ ๋ณ€ํ™”
let b = a๊ธฐ๋ณธ์ ์œผ๋กœ ์†Œ์œ ๊ถŒ ์ด๋™. Copy ํƒ€์ž…์ด๋ฉด ๊ฐ’ ๋ณต์‚ฌ
let b = &a๊ธฐ์กด ๊ฐ’์„ ๋นŒ๋ฆฌ๋Š” ์ฐธ์กฐ ์ƒ์„ฑ, ์†Œ์œ ๊ถŒ ์œ ์ง€
let b = a.clone()ํƒ€์ž…์˜ Clone ๊ตฌํ˜„ ์‹คํ–‰. ๋ณต์ œ ๋Œ€์ƒ์€ ํƒ€์ž…๋งˆ๋‹ค ๋‹ค๋ฆ„
let b = *boxed๋‚ด๋ถ€ ํƒ€์ž…์ด Copy์ด๋ฉด ๊ฐ’ ๋ณต์‚ฌ. i32๊ฐ€ ๊ทธ ์˜ˆ

Copy๋Š” ๊ฐ’์˜ ๋น„ํŠธ ๋ณต์‚ฌ๋ฅผ ํ—ˆ์šฉํ•˜๋Š” trait๋‹ค. clone์€ String์—์„œ๋Š” ๋ณ„๋„ ๋ฒ„ํผ๋ฅผ ๋ณต์ œํ•˜๊ณ  Rc์—์„œ๋Š” ๊ฐ™์€ ํ• ๋‹น์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์†Œ์œ ์ž๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

1.3 Smart Pointer์˜ ํ•„์š”์„ฑ

๊ฐ™์€ ๊ฐ’์„ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ์— ๋”ฐ๋ผ ํ•„์š”ํ•œ ํƒ€์ž…์ด ๋‹ฌ๋ผ์ง„๋‹ค.

  • ๊ณต์œ  ์†Œ์œ ๊ถŒ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ: Rc<T>๋กœ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ์ž ํ•„์š”ํ•œ ๋™์•ˆ ์†Œ์œ ํ•œ๋‹ค. ๋งˆ์ง€๋ง‰ ์†Œ์œ ์ž๊ฐ€ ๋†“์„ ๋•Œ๊นŒ์ง€ ๊ฐ’์ด ์œ ์ง€๋œ๋‹ค.
  • ๊ณต์œ  ์ฐธ์กฐ๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ: RefCell<T>๋Š” &RefCell<T>๋กœ๋„ ๋‚ด๋ถ€ ๊ฐ’์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ๋‚ด๋ถ€ ๊ฐ’์„ ๋นŒ๋ฆด ๋•Œ borrow ๊ทœ์น™์„ runtime์— ๊ฒ€์‚ฌํ•œ๋‹ค.

๋‘ ํƒ€์ž…์€ ๋…๋ฆฝ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 2ยท3์ ˆ์—์„œ ๊ฐ ํƒ€์ž…์„ ์‚ดํŽด๋ณด๊ณ , ๋‘ ์š”๊ตฌ๊ฐ€ ํ•จ๊ป˜ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์˜ Rc<RefCell<T>>๋Š” 4์ ˆ์—์„œ ๋‹ค๋ฃฌ๋‹ค.


2. Rc: A single-threaded reference-counting pointer

๊ฒŒ์ž„์˜ ์ „ํˆฌ ๊ธฐ๋Šฅ๊ณผ ํšŒ๋ณต ๊ธฐ๋Šฅ์ด ๊ฐ™์€ Player๋ฅผ ๋ณด๊ด€ํ•œ๋‹ค๊ณ  ํ•˜์ž.
๋‘ ๊ธฐ๋Šฅ์€ ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ์ ์— ๋“ฑ๋กยทํ•ด์ œ๋˜๋ฉฐ ์ „ํˆฌ ๊ธฐ๋Šฅ์ด ์ข…๋ฃŒ๋œ ๋’ค์—๋„ ํšŒ๋ณต ๊ธฐ๋Šฅ์ด ๋‚จ์•„ ์žˆ๋‹ค๋ฉด ๊ฐ™์€ Player๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

Player์˜ ๋ณต์‚ฌ๋ณธ์„ ๊ฐ๊ฐ ๋ณด๊ด€ํ•˜๋ฉด ๋‘ ๊ธฐ๋Šฅ์ด ์„œ๋กœ ๋‹ค๋ฅธ ์ƒํƒœ๋ฅผ ๋‹ค๋ฃจ๊ฒŒ ๋œ๋‹ค.
์•„๋ž˜ ์˜ˆ์‹œ์™€ ๊ฐ™์ด ์ „ํˆฌ ๊ธฐ๋Šฅ์ด Player๋ฅผ ์†Œ์œ ํ•˜๊ณ  ํšŒ๋ณต ๊ธฐ๋Šฅ์ด &Player๋ฅผ ๋นŒ๋ฆฌ๋ฉด ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ Player๋ฅผ ๋จผ์ € dropํ•  ์ˆ˜ ์—†๋‹ค.

struct Player {
    hp: i32,
}
 
fn main() {
    let combat = Player { hp: 100 };
    let healing: &Player = &combat;
 
    drop(combat); // ์ปดํŒŒ์ผ ์˜ค๋ฅ˜[E0505]: ์ดํ›„์—๋„ ์‚ฌ์šฉํ•  ์ฐธ์กฐ์˜ ๋Œ€์ƒ์„ dropํ•˜๋ ค ํ•จ
    assert_eq!(healing.hp, 100);
}

์ด๋Ÿฐ ๊ฒฝ์šฐ์— ๊ฐ ๊ธฐ๋Šฅ์ด Rc<Player>๋ฅผ ๋ณด์œ ํ•˜๋ฉด ํ•œ์ชฝ์ด ์ข…๋ฃŒ๋˜์–ด๋„ ๋‚จ์€ Rc๊ฐ€ ๊ฐ™์€ Player๋ฅผ ์œ ์ง€ํ•œ๋‹ค.

The type Rc<T> provides shared ownership of a value of type T, allocated in the heap.

use std::rc::Rc;
 
struct Player {
    hp: i32,
}
 
fn main() {
    let combat = Rc::new(Player { hp: 100 });
    let healing = Rc::clone(&combat); // Player๋ฅผ ๋ณต์ œํ•˜์ง€ ์•Š๊ณ  ๊ฐ™์€ ๊ฐ’์˜ ์†Œ์œ ์ž ์ถ”๊ฐ€
 
    assert!(Rc::ptr_eq(&combat, &healing)); // ๊ฐ™์€ heap ํ• ๋‹น
    assert_eq!(Rc::strong_count(&combat), 2);
 
    drop(combat); // strong: 2 โ†’ 1. healing์ด ์žˆ์œผ๋ฏ€๋กœ Player๋Š” ์œ ์ง€๋จ
    assert_eq!(healing.hp, 100); // ์ „ํˆฌ ๊ธฐ๋Šฅ์ด ์ข…๋ฃŒ๋œ ๋’ค์—๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ
    assert_eq!(Rc::strong_count(&healing), 1);
 
    drop(healing); // ๋งˆ์ง€๋ง‰ Rc๊ฐ€ drop๋˜๋ฉฐ Player๋„ ์ •๋ฆฌ๋จ
}

2.1 ์ฃผ์š” method

Rc API์˜ ๋ฐ˜ํ™˜ ๊ฐ’๊ณผ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ํ•จ๊ป˜ ์ฝ์œผ๋ฉด ๋ฉ”์„œ๋“œ์˜ ์—ญํ• ์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ‘œํ˜„๋ฐ˜ํ™˜ ๊ฐ’ํ• ๋‹น๊ณผ ์ƒํƒœ์˜ ๋ณ€ํ™”
Rc::new(value)Rc<T>์นด์šดํ„ฐ์™€ T๋ฅผ ๋‹ด๋Š” ๊ณต์œ  heap ํ• ๋‹น ์ƒ์„ฑ
Rc::clone(&a)Rc<T>๊ฐ™์€ ํ• ๋‹น์˜ ์†Œ์œ ์ž ์ถ”๊ฐ€, strong ์ฆ๊ฐ€
Rc::strong_count(&a)usizeํ˜„์žฌ strong count ์กฐํšŒ
Rc::ptr_eq(&a, &b)bool๊ฐ™์€ ๊ณต์œ  ํ• ๋‹น์ธ์ง€ ๋น„๊ต
Rc::downgrade(&a)Weak<T>Weak ์ถ”๊ฐ€, strong ์œ ์ง€
weak.upgrade()Option<Rc<T>>์„ฑ๊ณต ์‹œ ์†Œ์œ ์ž ์ถ”๊ฐ€, ๊ฐ’์ด ์—†์œผ๋ฉด None
Rc::get_mut(&mut a)Option<&mut T>๋‹ค๋ฅธ RcยทWeak๊ฐ€ ์—†์œผ๋ฉด ๋‚ด๋ถ€ ๊ฐ’ ์ˆ˜์ • ํ—ˆ์šฉ
Rc::make_mut(&mut a)&mut T๊ณต์œ  ์ƒํƒœ์— ๋”ฐ๋ผ ๋‚ด๋ถ€ ๊ฐ’ ๋ณต์ œ ๋˜๋Š” Weak ๋ถ„๋ฆฌ
drop(a)()strong ๊ฐ์†Œ, ๋งˆ์ง€๋ง‰์ด๋ฉด ๋‚ด๋ถ€ ๊ฐ’ drop

RAII: ๊ฐ์ฒด์˜ drop์— ์—ฐ๊ฒฐ๋˜๋Š” ์ •๋ฆฌ

์ž์›์˜ ๊ด€๋ฆฌ๋ฅผ ๊ฐ์ฒด์˜ ์ˆ˜๋ช…์— ์—ฐ๊ฒฐํ•˜๊ณ  drop๋  ๋•Œ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ์‹์ด RAII๋‹ค. scope ์ข…๋ฃŒ์— ๋”ฐ๋ฅธ ์ž๋™ drop๊ณผ drop(value)๋ฅผ ํ†ตํ•œ ๋ช…์‹œ์  drop์€ ๋ชจ๋‘ ๊ทธ ํƒ€์ž…์˜ ์ •๋ฆฌ ๋™์ž‘์„ ์‹คํ–‰ํ•œ๋‹ค.

  • Box<T>: ๋‚ด๋ถ€ T๋ฅผ dropํ•˜๊ณ  ์ž์‹ ์ด ์†Œ์œ ํ•œ heap ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•œ๋‹ค.
  • Rc<T>: strong count๋ฅผ ์ค„์ด๊ณ  ๋งˆ์ง€๋ง‰ Rc์ด๋ฉด ๋‚ด๋ถ€ T๋ฅผ dropํ•œ๋‹ค.

2.2 ์ƒ์„ฑ ํ•จ์ˆ˜์™€ ๋…๋ฆฝ์ ์ธ ๋ฐ์ดํ„ฐ ์ˆ˜๋ช…

์•ž ์˜ˆ์‹œ์—์„œ๋Š” ์ „ํˆฌ ๊ธฐ๋Šฅ์˜ Rc๋ฅผ dropํ•ด๋„ ํšŒ๋ณต ๊ธฐ๋Šฅ์˜ Rc๊ฐ€ Player๋ฅผ ์œ ์ง€ํ–ˆ๋‹ค. ๊ฐ’์„ ๋งŒ๋“  ํ•จ์ˆ˜๊ฐ€ ๋๋‚˜๋„ ๋‹ค๋ฅธ Rc๊ฐ€ ๋‚จ์•„ ์žˆ์œผ๋ฉด ๊ฐ™์€ ๊ฐ’์ด ์œ ์ง€๋œ๋‹ค.
์—ฌ๋Ÿฌ ๋ถ€๋ถ„์ด ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ณ  ๋งˆ์ง€๋ง‰๊นŒ์ง€ ์‚ฌ์šฉํ•  ๋ถ€๋ถ„์„ ์ปดํŒŒ์ผ ์‹œ์ ์— ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ Rc๋กœ ์†Œ์œ ๊ถŒ์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

โ€œโ€ฆwe canโ€™t determine at compile time which part will finish using the data last.โ€ (The Rust Programming Language)

Rc๋Š” ๊ณต์œ  ๊ฐ’๊ณผ ์นด์šดํ„ฐ๋ฅผ ํŠน์ • Rc ๋ณ€์ˆ˜์˜ ์ €์žฅ ๊ณต๊ฐ„๊ณผ ๋ถ„๋ฆฌ๋œ heap ํ• ๋‹น์— ๋‘”๋‹ค.
๊ฐ Rc๊ฐ€ ์ด ํ• ๋‹น์„ ๊ฐ€๋ฆฌํ‚ค๋ฏ€๋กœ ์ฒ˜์Œ ๋งŒ๋“  Rc๊ฐ€ drop๋˜๊ฑฐ๋‚˜ ์ƒ์„ฑ ํ•จ์ˆ˜๊ฐ€ ๋๋‚œ ๋’ค์—๋„ ๋‹ค๋ฅธ Rc๊ฐ€ ๊ฐ™์€ ๊ฐ’์„ ๊ณ„์† ์†Œ์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

use std::rc::Rc;
 
fn create() -> Rc<i32> {
    let a = Rc::new(10);
    let b = Rc::clone(&a);
    // ์ฒซ ๋ฒˆ์งธ ๋„์‹ ์‹œ์ : a์™€ b๊ฐ€ ๊ฐ™์€ ๊ฐ’์„ ์†Œ์œ ํ•œ๋‹ค.
    b // Rc ๊ฐ’์„ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์ด๋™
} // a๋Š” drop๋˜์–ด strong count๊ฐ€ 2์—์„œ 1๋กœ ๊ฐ์†Œ
 
fn main() {
    let retained = create();
    // ๋‘ ๋ฒˆ์งธ ๋„์‹ ์‹œ์ : create๋Š” ๋๋‚ฌ์ง€๋งŒ ๊ณต์œ  ๊ฐ’์€ ์œ ์ง€๋œ๋‹ค.
    assert_eq!(Rc::strong_count(&retained), 1);
    assert_eq!(*retained, 10);
}
flowchart LR
    subgraph RCL_BEFORE["1. create ๋ฐ˜ํ™˜ ์ง์ „"]
        subgraph RCL_CREATE_STACK["create์˜ Stack"]
            RCL_A["a: Rc ํฌ์ธํ„ฐ"]
            RCL_B["b: Rc ํฌ์ธํ„ฐ"]
        end
        subgraph RCL_BEFORE_HEAP["Heap"]
            RCL_DATA_BEFORE["strong 2 / i32 ๊ฐ’ 10"]
        end
        RCL_A -->|๊ณต์œ  ์†Œ์œ | RCL_DATA_BEFORE
        RCL_B -->|๊ณต์œ  ์†Œ์œ | RCL_DATA_BEFORE
    end
    subgraph RCL_AFTER["2. create ๋ฐ˜ํ™˜ ๋’ค"]
        subgraph RCL_MAIN_STACK["main์˜ Stack"]
            RCL_RETAINED["retained: Rc ํฌ์ธํ„ฐ"]
        end
        subgraph RCL_AFTER_HEAP["Heap"]
            RCL_DATA_AFTER["strong 1 / i32 ๊ฐ’ 10"]
        end
        RCL_RETAINED -->|๊ณต์œ  ์†Œ์œ | RCL_DATA_AFTER
    end
    RCL_B -.->|๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ Rc ์ด๋™| RCL_RETAINED
    RCL_DATA_BEFORE -.->|๊ฐ™์€ ํ• ๋‹น ์œ ์ง€| RCL_DATA_AFTER
  • ํ•จ์ˆ˜ ๋ฐ˜ํ™˜: b์˜ Rc ๊ฐ’์€ ๋ฐ˜ํ™˜๊ฐ’์„ ๊ฑฐ์ณ retained๋กœ ์ด๋™ํ•œ๋‹ค. ์ด ์ด๋™์€ ์†Œ์œ ์ž ์ˆ˜๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๊ณ  a์˜ drop๋งŒ strong count๋ฅผ 2์—์„œ 1๋กœ ์ค„์ธ๋‹ค.
  • ์ €์žฅ ๊ณต๊ฐ„: create์˜ stack frame์ด ๋๋‚˜๋„ ๊ฐ™์€ heap ํ• ๋‹น์€ ์œ ์ง€๋œ๋‹ค. retained๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ˆซ์ž๋Š” ์ƒ์„ฑ ๋•Œ์˜ 10์ด๋‹ค.

Rc์˜ borrow์™€ clone

  • &a๋Š” Rc ๋ณ€์ˆ˜ a ์ž์ฒด๋ฅผ ๋นŒ๋ฆฌ๋Š” &Rc<T>๋‹ค. strong count๋ฅผ ๋Š˜๋ฆฌ์ง€ ์•Š์œผ๋ฉฐ ์ด ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ์—๋Š” a๊ฐ€ ์œ ํšจํ•ด์•ผ ํ•œ๋‹ค.
  • Rc::clone(&a)๋Š” ๊ฐ™์€ heap ํ• ๋‹น์˜ ์†Œ์œ ์ž๋ฅผ ์ถ”๊ฐ€ํ•ด strong count๋ฅผ ๋Š˜๋ฆฐ๋‹ค. ์ƒˆ Rc๋Š” a๊ฐ€ drop๋œ ๋’ค์—๋„ ๋‚ด๋ถ€ ๊ฐ’์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

2.3 T์˜ ์ข…๋ฅ˜์™€ ๊ณต์œ  ํ• ๋‹น

Rc::new(value)๋Š” strongยทweak count์™€ value๋ฅผ ํ•จ๊ป˜ ๋‹ด๋Š” heap ํ• ๋‹น์„ ๋งŒ๋“ ๋‹ค. ์นด์šดํ„ฐ๋Š” ๊ฐ๊ฐ Cell<usize> ํ•„๋“œ์ด๊ณ  value๋Š” T ํ•„๋“œ๋กœ ๋‚ด๋ถ€ ๊ตฌ์กฐ์— ํฌํ•จ๋œ๋‹ค. ์ด ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ Box::new๋กœ ํ• ๋‹นํ•˜๋ฏ€๋กœ T๊ฐ€ ์ •์ˆ˜๋“  String์ด๋“  Rc์˜ heap ํ• ๋‹น์ด ์ƒ๊ธด๋‹ค.

Rc
use std::rc::Rc;
 
fn main() {
    let number = Rc::new(10);
    let text = Rc::new(String::from("hi"));
    let values = Rc::new(vec![10, 20, 30]);
    // ๋„์‹ ์‹œ์ : Rc ์„ธ ๊ฐœ๋ฅผ ๋งŒ๋“  ๋’ค
 
    assert_eq!(*number, 10);
    assert_eq!(text.as_str(), "hi");
    assert_eq!(values.as_slice(), &[10, 20, 30]);
}
flowchart TB
    subgraph RC_STACK["Stack"]
        RC_N["number: Rc ํฌ์ธํ„ฐ"]
        RC_S["text: Rc ํฌ์ธํ„ฐ"]
        RC_V["values: Rc ํฌ์ธํ„ฐ"]
    end
    subgraph RC_HEAP["Heap"]
        RC_N_DATA["Rc ํ• ๋‹น: strong 1 / i32 ๊ฐ’ 10"]
        RC_S_DATA["Rc ํ• ๋‹น: strong 1 / String ๊ด€๋ฆฌ ๊ฐ’"]
        RC_V_DATA["Rc ํ• ๋‹น: strong 1 / Vec ๊ด€๋ฆฌ ๊ฐ’"]
        RC_BYTES["๋ณ„๋„ UTF-8 ๋ฒ„ํผ: hi"]
        RC_ELEMENTS["<table style='border-collapse:collapse;table-layout:fixed;width:210px'><tr><td colspan='3' style='border:none;padding:0 0 6px'>๋ณ„๋„ Vec ๋ฒ„ํผ</td></tr><tr><td style='border:1px solid currentColor;padding:8px 0'>10</td><td style='border:1px solid currentColor;padding:8px 0'>20</td><td style='border:1px solid currentColor;padding:8px 0'>30</td></tr></table>"]
    end
    RC_N -->|๊ณต์œ  ์†Œ์œ | RC_N_DATA
    RC_S -->|๊ณต์œ  ์†Œ์œ | RC_S_DATA
    RC_V -->|๊ณต์œ  ์†Œ์œ | RC_V_DATA
    RC_S_DATA -->|String์ด ๋ฒ„ํผ ์†Œ์œ | RC_BYTES
    RC_V_DATA -->|Vec๊ฐ€ ๋ฒ„ํผ ์†Œ์œ | RC_ELEMENTS
  • Rc<i32>: ์ˆซ์ž๋„ Rc์˜ heap ํ• ๋‹น ์•ˆ์— ์žˆ๋‹ค. local variable number์—๋Š” ๊ทธ ํ• ๋‹น์„ ๊ฐ€๋ฆฌํ‚ค๋Š” Rc ๊ฐ’์ด ์žˆ๋‹ค.
  • Rc<String>ยทRc<Vec<i32>>: ๊ด€๋ฆฌ ๊ฐ’์ด ์นด์šดํ„ฐ์™€ ๊ฐ™์€ ํ• ๋‹น์— ํฌํ•จ๋œ๋‹ค. ๋ฌธ์žยท์›์†Œ ๋ฒ„ํผ๋Š” StringยทVec๊ฐ€ ์†Œ์œ ํ•˜๋Š” ๋ณ„๋„ ํ• ๋‹น์ด๋‹ค.
  • ๋ณต์ œ ๋ฒ”์œ„: ๊ธฐ์กด StringยทVec๋ฅผ Rc::new์— ๋„˜๊ธฐ๋ฉด ๊ด€๋ฆฌ ๊ฐ’์˜ ์†Œ์œ ๊ถŒ์ด ์ด๋™ํ•œ๋‹ค. ๋ฒ„ํผ ๋‚ด์šฉ์„ ๋ณต์‚ฌํ•˜๋Š” ํ˜ธ์ถœ์€ ์•„๋‹ˆ๋‹ค.

2.4 Weak์™€ ๋‚ด๋ถ€ ๊ฐ’์˜ ์ˆ˜๋ช…

๋ถ€๋ชจ๊ฐ€ ์ž์‹์„ Rc๋กœ ์†Œ์œ ํ•˜๊ณ  ์ž์‹๋„ ๋ถ€๋ชจ๋ฅผ Rc๋กœ ์†Œ์œ ํ•˜๋ฉด ์„œ๋กœ์˜ strong count๊ฐ€ ๋‚จ๋Š”๋‹ค.2 ์™ธ๋ถ€ ์†Œ์œ ์ž๊ฐ€ ์‚ฌ๋ผ์ ธ๋„ ์ด ์ˆœํ™˜ ๋•Œ๋ฌธ์— ๋‚ด๋ถ€ ๊ฐ’์ด ์ •๋ฆฌ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ์†Œ์œ ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ์—ญ๋ฐฉํ–ฅ ์—ฐ๊ฒฐ์—๋Š” Weak<T>๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

use std::rc::Rc;
 
fn main() {
    let owner = Rc::new(10);
    let weak = Rc::downgrade(&owner); // ๋ฐ˜ํ™˜ ํƒ€์ž…: Weak<i32>
    let temporary = weak.upgrade().unwrap(); // upgrade(): Option<Rc<i32>>, unwrap() ๋’ค: Rc<i32>
    assert_eq!(Rc::strong_count(&owner), 2);
    // ๋„์‹ ์‹œ์ : ๋‘ Rc ์†Œ์œ ์ž์™€ Weak๊ฐ€ ์กด์žฌํ•œ๋‹ค.
 
    drop(owner);
    assert_eq!(*temporary, 10);
    drop(temporary);
    assert!(weak.upgrade().is_none()); // upgrade(): Option<Rc<i32>>, ๋งˆ์ง€๋ง‰ Rc๊ฐ€ drop๋˜์–ด None
    drop(weak);
}
flowchart LR
    subgraph WEAK_STACK["Stack"]
        W_OWNER["owner: Rc"]
        W_TEMP["temporary: Rc"]
        W_WEAK["weak: Weak"]
    end
    subgraph WEAK_HEAP["Heap"]
        W_DATA["๊ด€๋ฆฌ ์ •๋ณด์™€ i32 ๊ฐ’ 10 / strong 2"]
    end
    W_OWNER -->|๊ณต์œ  ์†Œ์œ | W_DATA
    W_TEMP -->|๊ณต์œ  ์†Œ์œ | W_DATA
    W_WEAK -->|์ƒ์กด์„ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š” ์—ฐ๊ฒฐ| W_DATA
  • downgrade: ์›๋ž˜ Rc๋ฅผ ์œ ์ง€ํ•˜๊ณ  Weak๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. strong count๋Š” ๋Š˜๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
  • upgrade: ๋‚ด๋ถ€ ๊ฐ’์ด ์‚ด์•„ ์žˆ์œผ๋ฉด ์ƒˆ Rc๋ฅผ ๋‹ด์€ Some์„ ๋ฐ˜ํ™˜ํ•ด strong count๋ฅผ ๋Š˜๋ฆฐ๋‹ค. ๊ธฐ์กด Weak๋Š” ์œ ์ง€๋œ๋‹ค.
  • ๋งˆ์ง€๋ง‰ Rc์˜ ์ข…๋ฃŒ: ๋‚ด๋ถ€ T๊ฐ€ drop๋œ๋‹ค. Weak๊ฐ€ ๋‚จ์œผ๋ฉด ๊ด€๋ฆฌ ์ •๋ณด๋ฅผ ๋‹ด์€ ํ• ๋‹น ๊ณต๊ฐ„์€ ์œ ์ง€๋˜์ง€๋งŒ upgrade()๋Š” None์ด๋‹ค.
  • ๋งˆ์ง€๋ง‰ Weak์˜ ์ข…๋ฃŒ: Rc๊ฐ€ ์ด๋ฏธ ๋ชจ๋‘ ์‚ฌ๋ผ์ง„ ์ƒํƒœ๋ผ๋ฉด ๋‚จ์€ ํ• ๋‹น ๊ณต๊ฐ„๋„ ํ•ด์ œ๋œ๋‹ค.

์ผ๋ฐ˜ ์ฐธ์กฐ &T๋Š” ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ ๋Œ€์ƒ์ด ์œ ํšจํ•˜๋„๋ก compiler๊ฐ€ ๊ฒ€์‚ฌํ•œ๋‹ค. Weak๋Š” ๋Œ€์ƒ์˜ ์ˆ˜๋ช…์ด ๋๋‚œ ๋’ค์—๋„ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐ’์„ ์‚ฌ์šฉํ•  ๋•Œ upgrade()์˜ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•œ๋‹ค.

2.5 get_mut๊ณผ make_mut

Rc๋กœ ์†Œ์œ ํ•œ ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ์‹์€ ๊ณต์œ  ์ƒํƒœ์™€ ๋ณต์ œ ํ—ˆ์šฉ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค. ๋‘ ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋‘ ๋ณ€๊ฒฝํ•  Rc ์ž์ฒด๋ฅผ &mut Rc<T>๋กœ ๋ฐ›๋Š”๋‹ค.

  • get_mut: ๊ฐ™์€ ํ• ๋‹น์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋‹ค๋ฅธ RcยทWeak๊ฐ€ ์—†์œผ๋ฉด Some(&mut T)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์žˆ์œผ๋ฉด None์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • make_mut: ๋‹ค๋ฅธ Rc๊ฐ€ ์žˆ์œผ๋ฉด T๋ฅผ ๋ณต์ œํ•œ ์ƒˆ ํ• ๋‹น์œผ๋กœ ํ˜ธ์ถœ์ž์˜ Rc๋ฅผ ์—ฐ๊ฒฐํ•œ ๋’ค &mut T๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋‹ค๋ฅธ RcยทWeak๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ์กด ๊ฐ’์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋Ÿฐ ํ•„์š” ์‹œ ๋ณต์ œ๋ฅผ clone-on-write๋ผ๊ณ  ํ•œ๋‹ค.

๋ณต์ œ๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” make_mut์„ ๋ฐ”๋กœ ํ˜ธ์ถœํ•ด๋„ ๋œ๋‹ค. ์•„๋ž˜์—์„œ๋Š” ๋‘ ๋ฉ”์„œ๋“œ์˜ ์ฐจ์ด๋ฅผ ํ™•์ธํ•˜๋ ค๊ณ  ๊ณต์œ  ์ „ํ›„์— get_mut์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค. Player์— ๋ถ™์ธ #[derive(Clone)]์€ make_mut์ด ํ•„์š”ํ•  ๋•Œ Player๋ฅผ ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

use std::rc::Rc;
 
#[derive(Clone)]
struct Player {
    hp: i32,
}
 
fn main() {
    let mut combat = Rc::new(Player { hp: 100 });
 
    Rc::get_mut(&mut combat).unwrap().hp -= 10; // ๋‹จ๋… ์†Œ์œ : ๊ธฐ์กด Player ์ˆ˜์ •
    assert_eq!(combat.hp, 90);
 
    let healing = Rc::clone(&combat); // ๊ฐ™์€ Player์˜ ์†Œ์œ ์ž ์ถ”๊ฐ€
    assert_eq!(Rc::strong_count(&combat), 2);
    assert!(Rc::get_mut(&mut combat).is_none()); // ๊ณต์œ  ์ค‘์ด๋ฏ€๋กœ ๊ฐ€๋ณ€ ์ ‘๊ทผ ๊ฑฐ๋ถ€
    // ๋„์‹ ์‹œ์  โ‘ : ๋‘ Rc๊ฐ€ ์ฒด๋ ฅ 90์ธ ๊ฐ™์€ Player๋ฅผ ์†Œ์œ ํ•œ๋‹ค.
 
    Rc::make_mut(&mut combat).hp -= 30; // Player๋ฅผ ๋ณต์ œํ•œ ๋’ค combat ์ชฝ๋งŒ ์ˆ˜์ •
    assert_eq!(combat.hp, 60);
    assert_eq!(healing.hp, 90);
    assert!(!Rc::ptr_eq(&combat, &healing));
    assert_eq!(Rc::strong_count(&combat), 1);
    assert_eq!(Rc::strong_count(&healing), 1);
    // ๋„์‹ ์‹œ์  โ‘ก: combat๊ณผ healing์ด ์„œ๋กœ ๋‹ค๋ฅธ Player๋ฅผ ์†Œ์œ ํ•œ๋‹ค.
}

์‹œ์  โ‘ ์—์„œ๋Š” ๋‹จ๋… ์†Œ์œ  ์ค‘์— ์ฒด๋ ฅ์„ 90์œผ๋กœ ์ˆ˜์ •ํ•œ ๋’ค ๋‘ Rc๊ฐ€ ๊ฐ™์€ Player๋ฅผ ์†Œ์œ ํ•œ๋‹ค.

flowchart TB
    subgraph RC_MUT_BEFORE_STACK["Stack: โ‘  make_mut ํ˜ธ์ถœ ์ „"]
        RC_MUT_BEFORE_COMBAT["combat: Rc"]
        RC_MUT_BEFORE_HEALING["healing: Rc"]
    end
    subgraph RC_MUT_BEFORE_HEAP["Heap"]
        RC_MUT_BEFORE_DATA["๊ฐ™์€ Rc ํ• ๋‹น: strong 2 / Player์˜ hp: 90"]
    end
    RC_MUT_BEFORE_COMBAT -->|๊ณต์œ  ์†Œ์œ | RC_MUT_BEFORE_DATA
    RC_MUT_BEFORE_HEALING -->|๊ณต์œ  ์†Œ์œ | RC_MUT_BEFORE_DATA
  • combatยทhealing์€ ๊ฐ™์€ heap ํ• ๋‹น์„ ์†Œ์œ ํ•œ๋‹ค. get_mut์€ ๋‹ค๋ฅธ Rc๊ฐ€ ๋‚จ์•„ ์žˆ์–ด None์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์‹œ์  โ‘ก์—์„œ๋Š” make_mut์ด Player๋ฅผ ๋ณต์ œํ•˜๊ณ  combat์„ ์ƒˆ ํ• ๋‹น์œผ๋กœ ์—ฐ๊ฒฐํ•œ ๋’ค ์ฒด๋ ฅ์„ 60์œผ๋กœ ๋ฐ”๊พผ๋‹ค.

flowchart TB
    subgraph RC_MUT_AFTER_STACK["Stack: โ‘ก make_mut์œผ๋กœ ์ˆ˜์ •ํ•œ ๋’ค"]
        RC_MUT_AFTER_COMBAT["combat: Rc"]
        RC_MUT_AFTER_HEALING["healing: Rc"]
    end
    subgraph RC_MUT_AFTER_HEAP["Heap์˜ ์„œ๋กœ ๋‹ค๋ฅธ ํ• ๋‹น"]
        RC_MUT_AFTER_NEW["์ƒˆ ํ• ๋‹น: strong 1 / Player์˜ hp: 60"]
        RC_MUT_AFTER_ORIGINAL["๊ธฐ์กด ํ• ๋‹น: strong 1 / Player์˜ hp: 90"]
    end
    RC_MUT_AFTER_COMBAT -->|๋‹จ๋… ์†Œ์œ | RC_MUT_AFTER_NEW
    RC_MUT_AFTER_HEALING -->|๋‹จ๋… ์†Œ์œ | RC_MUT_AFTER_ORIGINAL
  • healing์€ ๊ธฐ์กด Player๋ฅผ ๊ณ„์† ์†Œ์œ ํ•˜๋ฏ€๋กœ ์ฒด๋ ฅ์€ 90์œผ๋กœ ์œ ์ง€๋œ๋‹ค. ๋‘ ๊ธฐ๋Šฅ์ด ๊ฐ™์€ ์ฒด๋ ฅ์˜ ๋ณ€๊ฒฝ์„ ๊ณต์œ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” 4์ ˆ์—์„œ ๋‹ค๋ฃฌ๋‹ค.
  • T๊ฐ€ StringยทVec์ด๋ฉด Clone ๊ตฌํ˜„์— ๋”ฐ๋ผ ๋‚ด๋ถ€ ๋ฒ„ํผ๋„ ๋ณต์ œ๋œ๋‹ค. Rc์˜ ๊ณต์œ  ํ• ๋‹น๊ณผ ๊ทธ ์•ˆ์˜ T๊ฐ€ ์†Œ์œ ํ•˜๋Š” ๋ณ„๋„ ๋ฒ„ํผ๋ฅผ ๊ตฌ๋ถ„ํ•œ๋‹ค.

๋‹ค๋ฅธ Rc ์—†์ด Weak๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

์ž๊ธฐ Rc ์™ธ์— Weak๋งŒ ์žˆ์œผ๋ฉด get_mut์€ None์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. make_mut์€ T๋ฅผ cloneํ•˜์ง€ ์•Š๊ณ  Weak์™€ ๊ฐ’์˜ ์—ฐ๊ฒฐ์„ ๋ถ„๋ฆฌํ•˜๋ฉฐ, ๊ธฐ์กด Weak์˜ upgrade()๋Š” None์ด ๋œ๋‹ค.


3. RefCell: Dynamically checked borrow rules

์•ž ์ ˆ์˜ ์ „ํˆฌยทํšŒ๋ณต ์˜ˆ์‹œ์—์„œ ์ด๋ฒˆ์—๋Š” Player์˜ ์ฒด๋ ฅ ๋ณ€๊ฒฝ์„ ์‚ดํŽด๋ณธ๋‹ค. ์ „ํˆฌ๋Š” ์ฒด๋ ฅ์„ ์ค„์ด๊ณ  ํšŒ๋ณต์€ ๋Š˜๋ฆฌ๋ฉฐ ๋‘ ๊ธฐ๋Šฅ์ด ๊ฐ™์€ ๊ฐ’์˜ ๋ณ€๊ฒฝ์„ ๊ณต์œ ํ•ด์•ผ ํ•œ๋‹ค. 2.5์ ˆ์˜ make_mut ์˜ˆ์ œ์ฒ˜๋Ÿผ Player๋ฅผ ๋ณต์ œํ•ด ๋ถ„๋ฆฌํ•˜๋ฉด ์ด ์š”๊ตฌ๋ฅผ ๋งŒ์กฑํ•˜์ง€ ๋ชปํ•œ๋‹ค.

์•„๋ž˜์—์„œ๋Š” ์ ‘๊ทผ ๋ฌธ์ œ๋ฅผ ์‚ดํŽด๋ณด๊ธฐ ์œ„ํ•ด ํ•˜๋‚˜์˜ local variable player๋ฅผ ๋‘ ๊ธฐ๋Šฅ์ด ๋นŒ๋ฆฐ๋‹ค. ๋‘ ๊ธฐ๋Šฅ์€ ์ฐธ์กฐ๋ฅผ ๊ฐ์ž ๋ณด๊ด€ํ•ด ์—ฌ๋Ÿฌ ์ด๋ฒคํŠธ์—์„œ ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ๋‘ ์ฐธ์กฐ combatยทhealing์„ ๋ชจ๋‘ &mut Player๋กœ ๋งŒ๋“ค๋ ค๋Š” ์ฝ”๋“œ๋Š” ์ปดํŒŒ์ผ๋˜์ง€ ์•Š๋Š”๋‹ค.

struct Player {
    hp: i32,
}
 
fn main() {
    let mut player = Player { hp: 100 };
    let combat = &mut player;
    let healing = &mut player; // ์ปดํŒŒ์ผ ์˜ค๋ฅ˜: ๊ฐ€๋ณ€ borrow๊ฐ€ ๊ฒน์นจ
 
    combat.hp -= 30;
    healing.hp += 20;
    combat.hp -= 10;
}

healing์„ ๋งŒ๋“  ๋’ค์—๋„ combat์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์ฒซ ๋ฒˆ์งธ ๊ฐ€๋ณ€ borrow๊ฐ€ ๋๋‚˜์ง€ ์•Š๋Š”๋‹ค. ์ฒด๋ ฅ์„ ๋ฐ”๊พธ๋Š” ๋ฌธ์žฅ์€ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋”๋ผ๋„ ๋‘ ๊ฐ€๋ณ€ ์ฐธ์กฐ๋ฅผ ์ด ํ˜•ํƒœ๋กœ ํ•จ๊ป˜ ๋ณด๊ด€ํ•  ์ˆ˜ ์—†๋‹ค.

RefCell<T>๋Š” borrow ๊ทœ์น™์„ runtime์— ๊ฒ€์‚ฌํ•ด ์ด๋Ÿฐ ์ ‘๊ทผ์„ ์ œ๊ณตํ•œ๋‹ค.

A mutable memory location with dynamically checked borrow rules

3.1 guard์™€ ์ฃผ์š” method

RefCell์˜ ์ฃผ์š” method์ธ borrow()ยทborrow_mut()์„ ํ˜ธ์ถœํ•  ๋•Œ ํ˜„์žฌ borrow์™€ ์ถฉ๋Œํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ๊ฐ€ ํ•„์š”ํ•˜๊ณ  ์ดํ›„์˜ ์š”์ฒญ๋„ ๊ฒ€์‚ฌํ•˜๋ ค๋ฉด ์•ž์„œ ํ—ˆ์šฉํ•œ borrow๊ฐ€ ์–ธ์ œ ๋ฐ˜๋‚ฉ๋˜๋Š”์ง€ runtime์— ๊ธฐ๋กํ•ด์•ผ ํ•œ๋‹ค. (์ผ๋ฐ˜ ์ฐธ์กฐ &Tยท&mut T ์ž์ฒด๋Š” ์‚ฌ์šฉ์ด ๋๋‚  ๋•Œ RefCell์˜ borrow ์ƒํƒœ๋ฅผ ๊ฐฑ์‹ ํ•˜์ง€ ์•Š๋Š”๋‹ค)

์ด๋ฅผ ์œ„ํ•ด RefCell์€ ๊ฐ’์— ์ ‘๊ทผํ•˜๋Š” ๋™์•ˆ borrow๋ฅผ ์œ ์ง€ํ•˜๋Š” guard ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. guard๊ฐ€ drop๋  ๋•Œ RefCell์˜ borrow ์ƒํƒœ๋ฅผ ๊ฐฑ์‹ ํ•ด ์ ‘๊ทผ์„ ๋ฐ˜๋‚ฉํ•œ๋‹ค. ๋‚ด๋ถ€ T์˜ ์†Œ์œ ๊ถŒ์€ ๊ณ„์† RefCell์— ๋‚จ๋Š”๋‹ค.

  • ์ฝ๊ธฐ guard: Ref<'b, T>. Deref๋กœ ๋‚ด๋ถ€ ๊ฐ’์„ &T๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.
  • ์“ฐ๊ธฐ guard: RefMut<'b, T>. Deref๋กœ ์ฝ๊ณ  DerefMut์œผ๋กœ ๋‚ด๋ถ€ ๊ฐ’์„ &mut T๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

T๋Š” ๋นŒ๋ฆฌ๋Š” ๋‚ด๋ถ€ ๊ฐ’์ด๊ณ  'b๋Š” guard๊ฐ€ RefCell์„ ๋นŒ๋ฆฌ๋Š” lifetime์ด๋‹ค. Player๋ฅผ ๋นŒ๋ฆฌ๋Š” ์˜ˆ์ œ์—์„œ๋Š” Ref<'_, Player>ยทRefMut<'_, Player>๋กœ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ '_์˜ lifetime์€ compiler๊ฐ€ ์ถ”๋ก ํ•œ๋‹ค.

ํ˜„์žฌ ๊ตฌํ˜„์€ isize ์นด์šดํ„ฐ๋กœ borrow ์ข…๋ฅ˜์™€ ๊ฐœ์ˆ˜๋ฅผ ํ•จ๊ป˜ ๊ธฐ๋กํ•œ๋‹ค.

  • 0์€ ๋นŒ๋ฆผ ์—†์Œ
  • ์–‘์ˆ˜ n์€ ์ฝ๊ธฐ guard n๊ฐœ
  • ์Œ์ˆ˜๋Š” ์“ฐ๊ธฐ borrow ์œ ์ง€ ์ค‘์ž„์„ ์˜๋ฏธ (์ผ๋ฐ˜์ ์ธ borrow_mut() ์งํ›„์˜ ๊ฐ’์€ -1)

์•„๋ž˜ ํ‘œ๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์— ๋”ฐ๋ฅธ borrow ์ƒํƒœ์™€ ๊ฐ’์˜ ๋ณ€ํ™”๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

๋ฉ”์„œ๋“œ ์›ํ˜•์ƒํƒœ์™€ ๊ฐ’์˜ ๋ณ€ํ™”Borrow ์ถฉ๋Œ ๊ฒ€์‚ฌ์™€ ์ ‘๊ทผ ์กฐ๊ฑด
pub const fn new(value: T) -> RefCell<T>๋‚ด๋ถ€ ๊ฐ’๊ณผ ์นด์šดํ„ฐ 0 ์ƒ์„ฑ์ƒˆ RefCell ์ƒ์„ฑ
pub fn borrow(&self) -> Ref<'_, T>์ฝ๊ธฐ ์„ฑ๊ณต ์‹œ n โ†’ n + 1์“ฐ๊ธฐ ์ค‘์ธ n < 0์ด๋ฉด panic
pub fn borrow_mut(&self) -> RefMut<'_, T>์“ฐ๊ธฐ ์„ฑ๊ณต ์‹œ 0 โ†’ -1๋‹ค๋ฅธ borrow๊ฐ€ ์žˆ๋Š” n != 0์ด๋ฉด panic
pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError>์ฝ๊ธฐ ์„ฑ๊ณต ์‹œ n โ†’ n + 1n < 0์ด๋ฉด Err
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError>์“ฐ๊ธฐ ์„ฑ๊ณต ์‹œ 0 โ†’ -1n != 0์ด๋ฉด Err
pub fn replace(&self, t: T) -> T๋‚ด๋ถ€ T ๊ต์ฒดยท๊ธฐ์กด T์˜ ์†Œ์œ ๊ถŒ ๋ฐ˜ํ™˜, ํ˜ธ์ถœ ๋’ค ์นด์šดํ„ฐ 0๋‹ค๋ฅธ borrow๊ฐ€ ์žˆ๋Š” n != 0์ด๋ฉด panic
pub fn get_mut(&mut self) -> &mut Truntime borrow ๊ฒ€์‚ฌ ์—†์ด ๋‚ด๋ถ€ ๊ฐ’ ์ ‘๊ทผ&mut self๋กœ ๋ฐฐํƒ€ ์ ‘๊ทผ ํ™•๋ณด
pub const fn into_inner(self) -> TRefCell์„ ์†Œ๋น„ํ•˜๊ณ  T์˜ ์†Œ์œ ๊ถŒ ๋ฐ˜ํ™˜self ์†Œ์œ ๊ถŒ ํ•„์š”

์‹คํŒจํ•œ borrow ์š”์ฒญ์€ ์นด์šดํ„ฐ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค. ์—ฌ๋Ÿฌ ์ฝ๊ธฐ borrow๋ฅผ ํ•จ๊ป˜ ์œ ์ง€ํ•˜๊ฑฐ๋‚˜ ์“ฐ๊ธฐ borrow ํ•˜๋‚˜๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ๋Š” ๊ฒน์น  ์ˆ˜ ์—†๋‹ค.

  • ์ถฉ๋Œ ์ฒ˜๋ฆฌ์˜ ์„ ํƒ
    • borrow()ยทborrow_mut()์€ ์ถฉ๋Œ์„ ํ”„๋กœ๊ทธ๋žจ ์˜ค๋ฅ˜๋กœ ์ทจ๊ธ‰ํ•ด panic
    • ์‹คํŒจ ์‹œ ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•˜๊ฑฐ๋‚˜ ๋‚˜์ค‘์— ๋‹ค์‹œ ์‹œ๋„ํ•˜๋ ค๋ฉด try_borrow()ยทtry_borrow_mut()์˜ Result๋ฅผ match๋‚˜ if let์œผ๋กœ ์ฒ˜๋ฆฌ
  • unwrap์˜ ๋™์ž‘
    • borrow()์™€ try_borrow().unwrap()์€ ์„ฑ๊ณตํ•˜๋ฉด ๊ฐ™์€ ์ข…๋ฅ˜์˜ ์ฝ๊ธฐ guard๋ฅผ ์–ป๊ณ  ์ถฉ๋Œํ•˜๋ฉด ๋‘˜ ๋‹ค panic
      • borrow()๋Š” RefCell ๋‚ด๋ถ€์—์„œ, try_borrow().unwrap()์€ ๋ฐ˜ํ™˜๋œ Err๋ฅผ unwrap()ํ•˜๋Š” ๊ณผ์ •์—์„œ panic
    • ์“ฐ๊ธฐ ์ ‘๊ทผ์ธ borrow_mut()์™€ try_borrow_mut().unwrap()๋„ ๊ฐ™์€ ๊ด€๊ณ„์ด๋ฏ€๋กœ ์‹คํŒจ ์‹œ panic์„ ํ—ˆ์šฉํ•˜๋Š” ์ฝ”๋“œ์—์„œ๋Š” ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๊ฐ„๋‹จ

get_mut()์€ compiler๊ฐ€ &mut RefCell<T>์˜ ๋ฐฐํƒ€ ์ ‘๊ทผ์„ ๋ณด์žฅํ•˜๋Š” ๊ฒฝ์šฐ๋‹ค. into_inner()๋Š” ๋‚ด๋ถ€ ๊ฐ’์„ ๋นŒ๋ฆฌ๋Š” ํ˜ธ์ถœ๊ณผ ๋‹ฌ๋ฆฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์†Œ๋น„ํ•œ๋‹ค.

Borrow์˜ ์ข…๋ฃŒ ์‹œ์ : ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ๊ณผ guard์˜ drop

์ผ๋ฐ˜ ์ฐธ์กฐ &Tยท&mut T๋Š” ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ ์ดํ›„ compiler์˜ ํŒ๋‹จ์— ์˜ํ•ด borrow๊ฐ€ ๋๋‚  ์ˆ˜ ์žˆ๋‹ค.
ํ•˜์ง€๋งŒ RefยทRefMut guard๋Š” ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ๊ณผ ๋ณ„๊ฐœ๋กœ drop๋  ๋•Œ borrow๋ฅผ ๋ฐ˜๋‚ฉํ•œ๋‹ค.

3.2 Player์˜ ๊ณต์œ  ์ฐธ์กฐ์™€ ๋‚ด๋ถ€ ๋ณ€๊ฒฝ

Player๋ฅผ RefCell๋กœ ๊ฐ์‹ธ๋ฉด ๋‘ ๊ธฐ๋Šฅ์€ &RefCell<Player>๋ฅผ ๋ณด๊ด€ํ•œ๋‹ค. ๊ฐ ๊ธฐ๋Šฅ์€ ์ฒด๋ ฅ์„ ํ™•์ธํ•  ๋•Œ ์ฝ๊ธฐ guard๋ฅผ, ๋ณ€๊ฒฝํ•  ๋•Œ ์“ฐ๊ธฐ guard๋ฅผ ์–ป๋Š”๋‹ค. ๋‘ ๊ธฐ๋Šฅ์˜ ๊ณต์œ  ์ฐธ์กฐ๋Š” ํ•จ๊ป˜ ์œ ์ง€ํ•˜๋ฉด์„œ ๋‚ด๋ถ€ Player๋ฅผ ๋นŒ๋ฆฌ๋Š” ์‹œ์ ์„ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.

use std::cell::{Ref, RefCell, RefMut};
 
struct Player {
    hp: i32,
}
 
fn main() {
    let player = RefCell::new(Player { hp: 100 });
    let combat: &RefCell<Player> = &player;
    let healing: &RefCell<Player> = &player;
 
    let combat_view: Ref<'_, Player> = combat.borrow(); // Ref<Player>: ์ฝ๊ธฐ guard. 0 โ†’ 1
    let healing_view: Ref<'_, Player> = healing.borrow(); // Ref<Player>: ์ฝ๊ธฐ guard ์ถ”๊ฐ€. 1 โ†’ 2
    assert_eq!(combat_view.hp, 100);
    assert_eq!(healing_view.hp, 100);
    assert!(combat.try_borrow_mut().is_err()); // Err: ์ฝ๊ธฐ guard ์œ ์ง€ ์ค‘. ์นด์šดํ„ฐ 2 ์œ ์ง€
 
    drop(combat_view); // 2 โ†’ 1
    drop(healing_view); // 1 โ†’ 0: ๋งˆ์ง€๋ง‰ ์ฝ๊ธฐ guard ๋ฐ˜๋‚ฉ
 
    {
        let mut writer: RefMut<'_, Player> = combat.borrow_mut(); // RefMut<Player>: ์“ฐ๊ธฐ guard. 0 โ†’ -1
        writer.hp -= 30; // 100 โ†’ 70
        assert!(healing.try_borrow().is_err()); // Err: ์“ฐ๊ธฐ guard ์œ ์ง€ ์ค‘. ์นด์šดํ„ฐ -1 ์œ ์ง€
        // ๋„์‹ ์‹œ์  โ‘ : ์ „ํˆฌ์˜ writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
    } // writer๊ฐ€ drop๋˜๋ฉฐ ์“ฐ๊ธฐ borrow ๋ฐ˜๋‚ฉ. -1 โ†’ 0
 
    if let Ok(mut writer) = healing.try_borrow_mut() {
        writer.hp += 20; // 70 โ†’ 90. ์“ฐ๊ธฐ borrow๋ฅผ ์–ป์—ˆ์„ ๋•Œ๋งŒ ํšŒ๋ณต
    } // ์„ฑ๊ณตํ•œ ์“ฐ๊ธฐ borrow๋ฅผ ๋ฐ˜๋‚ฉ
 
    combat.borrow_mut().hp -= 10; // 90 โ†’ 80. ์ž„์‹œ guard๋Š” ๋ฌธ์žฅ ๋์—์„œ drop
    assert_eq!(healing.borrow().hp, 80); // ์ž„์‹œ ์ฝ๊ธฐ guard๋„ ๋ฌธ์žฅ ๋์—์„œ drop
    // ๋„์‹ ์‹œ์  โ‘ก: ๋ชจ๋“  guard๋ฅผ ๋ฐ˜๋‚ฉํ•˜๊ณ  ๋‘ ๊ณต์œ  ์ฐธ์กฐ๋งŒ ๋‚จ์€ ๋’ค
}

์ด ์˜ˆ์ œ์—์„œ player๋Š” let mut ์—†์ด ์„ ์–ธํ–ˆ๊ณ  combatยทhealing์€ ๊ณต์œ  ์ฐธ์กฐ &RefCell<Player>๋‹ค. ๊ทธ ์ฐธ์กฐ๋กœ borrow_mut()์„ ํ˜ธ์ถœํ•ด ์–ป์€ RefMut<Player> guard๋ฅผ ์ด์šฉํ•ด Player์˜ ์ฒด๋ ฅ์„ ์ˆ˜์ •ํ•œ๋‹ค.

๊ณต์œ  ์ฐธ์กฐ๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฐ์ฒด์˜ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์„ฑ์งˆ์„ ๋‚ด๋ถ€ ๊ฐ€๋ณ€์„ฑ์ด๋ผ ํ•œ๋‹ค.

  • ๋‘ ๊ธฐ๋Šฅ์˜ ์ฝ๊ธฐ
    • combat_viewยทhealing_view๋Š” ๊ฐ™์€ Player๋ฅผ ์ฝ๋Š” guard๋กœ ๋‘˜์ด ์œ ์ง€๋˜๋Š” ๋™์•ˆ ์ฒซ try_borrow_mut()์€ Err๋ฅผ ๋ฐ˜ํ™˜
    • ๋‘ drop์„ ์ƒ๋žตํ•˜๋ฉด ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ์ด ๋๋‚ฌ์–ด๋„ ์ฝ๊ธฐ borrow๊ฐ€ ๋‚จ์•„ ๋’ค์˜ combat.borrow_mut()์—์„œ panic
  • ์ „ํˆฌ ์ค‘์˜ ์ ‘๊ทผ
    • writer.hp๋Š” guard์˜ dereference๋กœ RefCell ์•ˆ์˜ Player์— ์ ‘๊ทผ
    • ์ด ์“ฐ๊ธฐ guard๊ฐ€ ์œ ์ง€๋˜๋Š” ๋™์•ˆ healing.try_borrow()๋„ Err๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ๋ธ”๋ก ๋์—์„œ writer๊ฐ€ drop๋œ ๋’ค ๋‹ค์‹œ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜ ์žˆ์Œ
  • ํšŒ๋ณต๊ณผ ๋‹ค์Œ ์ „ํˆฌ
    • if let Ok(...)๋Š” ์“ฐ๊ธฐ borrow๋ฅผ ์–ป์œผ๋ฉด ํšŒ๋ณตํ•˜๊ณ  ์ถฉ๋Œํ•˜๋ฉด ์ด๋ฒˆ ํšŒ๋ณต์„ ๊ฑด๋„ˆ๋œ€
    • ๋งˆ์ง€๋ง‰ ์ „ํˆฌ์ฒ˜๋Ÿผ guard๋ฅผ ๋ณ€์ˆ˜์— ๋‹ด์ง€ ์•Š๊ณ  combat.borrow_mut().hp๋กœ ์ ‘๊ทผํ•˜๋ฉด ์ด ๋ฌธ์žฅ์˜ ์ž„์‹œ guard๋Š” ๋ฌธ์žฅ ๋์—์„œ drop๋œ๋‹ค.
flowchart TB
    subgraph PA_STACK["Stack: โ‘  ์ „ํˆฌ์˜ writer ์œ ์ง€ ์ค‘"]
        PA_COMBAT["combat: RefCell์„ ๋นŒ๋ฆฌ๋Š” ๊ณต์œ  ์ฐธ์กฐ"]
        PA_HEALING["healing: RefCell์„ ๋นŒ๋ฆฌ๋Š” ๊ณต์œ  ์ฐธ์กฐ"]
        PA_WRITER["writer: RefMut guard"]
        subgraph PA_CELL["player: RefCell ๊ฐ’"]
            PA_STATE["borrow ์นด์šดํ„ฐ: -1"]
            PA_VALUE["Player ๊ฐ’ / hp: 70"]
        end
    end
    PA_COMBAT -->|๊ณต์œ  ์ฐธ์กฐ| PA_CELL
    PA_HEALING -->|๊ณต์œ  ์ฐธ์กฐ| PA_CELL
    PA_WRITER -->|Player ๊ฐ’ ๋นŒ๋ฆผ| PA_VALUE
    PA_WRITER -->|borrow ์ƒํƒœ ์ถ”์ | PA_STATE
flowchart TB
    subgraph PB_STACK["Stack: โ‘ก ๋ชจ๋“  guard ๋ฐ˜๋‚ฉ ํ›„"]
        PB_COMBAT["combat: RefCell์„ ๋นŒ๋ฆฌ๋Š” ๊ณต์œ  ์ฐธ์กฐ"]
        PB_HEALING["healing: RefCell์„ ๋นŒ๋ฆฌ๋Š” ๊ณต์œ  ์ฐธ์กฐ"]
        PB_CELL["player: RefCell ๊ฐ’ / borrow ์นด์šดํ„ฐ: 0 / Player์˜ hp: 80"]
    end
    PB_COMBAT -->|๊ณต์œ  ์ฐธ์กฐ| PB_CELL
    PB_HEALING -->|๊ณต์œ  ์ฐธ์กฐ| PB_CELL

3.3 i32ยทStringยทVec์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ

RefCell<T>๋Š” borrow ์ƒํƒœ์™€ UnsafeCell<T>๋ฅผ ํ•„๋“œ๋กœ ๋‹ด๋Š”๋‹ค. UnsafeCell<T>๋Š” T๋ฅผ ์ž์‹ ์˜ ์ €์žฅ ๊ณต๊ฐ„ ์•ˆ์— ๋‹ด๋Š” wrapper๋‹ค.

์•„๋ž˜ ์„ธ ์˜ˆ์ œ๋Š” RefCell์„ local variable์— ๋‘๊ณ  writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•˜๋Š” ์‹œ์ ์˜ ์ €์žฅ ๊ตฌ์กฐ๋ฅผ ๋น„๊ตํ•œ๋‹ค.

RefCell<i32>
use std::cell::RefCell;
 
fn main() {
    let cell = RefCell::new(10);
 
    {
        let mut writer = cell.borrow_mut();
        *writer += 1;
        // ๋„์‹ ์‹œ์ : writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
    }
 
    assert_eq!(*cell.borrow(), 11);
}
flowchart TB
    subgraph STACK["Stack"]
        WRITER["writer: RefMut guard"]
        subgraph CELL["cell: RefCell ๊ฐ’"]
            STATE["borrow ์ƒํƒœ: ์“ฐ๊ธฐ ์ค‘ / ์นด์šดํ„ฐ -1"]
            VALUE["๋‚ด๋ถ€ i32 ๊ฐ’: 11"]
        end
    end
    WRITER -->|๋‚ด๋ถ€ ๊ฐ’ ์ ‘๊ทผ| VALUE
    WRITER -->|borrow ์ƒํƒœ ์ถ”์ | STATE
  • i32์˜ ์ €์žฅ ์œ„์น˜: ์ƒํƒœ ์ •๋ณด์™€ ์ˆซ์ž 11์€ ๋ชจ๋‘ local variable cell ์•ˆ์— ์žˆ๋‹ค. RefCell::new(10)์€ ์ˆซ์ž๋ฅผ heap์— ๋”ฐ๋กœ ๋ฐฐ์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • guard์˜ ์ ‘๊ทผ ๋Œ€์ƒ: *writer๋กœ RefCell ์•ˆ์˜ i32๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค. writer๋Š” ๋‚ด๋ถ€ ๊ฐ’์„ ๋นŒ๋ฆฌ๋Š” guard์ด๋ฉฐ ์ˆซ์ž์˜ ๋ณต์‚ฌ๋ณธ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
RefCell<String>

RefCell<String>์€ borrow ์ƒํƒœ์™€ String์˜ ํฌ์ธํ„ฐยท๊ธธ์ดยทcapacity๋ฅผ ํ•จ๊ป˜ ๋‹ด๊ณ  RefCell<Vec<i32>>๋Š” borrow ์ƒํƒœ์™€ Vec์˜ ํฌ์ธํ„ฐยท๊ธธ์ดยทcapacity๋ฅผ ํ•จ๊ป˜ ๋‹ด๋Š”๋‹ค. ๋ฌธ์ž์—ด ๋ฐ”์ดํŠธ์™€ Vec ์›์†Œ๋Š” ๊ฐ๊ฐ ๋ณ„๋„ heap ๋ฒ„ํผ์— ์žˆ๋‹ค.

use std::cell::RefCell;
 
fn main() {
    let text = RefCell::new(String::from("hi"));
 
    {
        let mut writer = text.borrow_mut();
        writer.push_str(" Rust");
        assert_eq!(writer.as_str(), "hi Rust");
        // ๋„์‹ ์‹œ์ : writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
    }
 
    assert_eq!(text.borrow().as_str(), "hi Rust");
}
flowchart TB
    subgraph RS_STACK["Stack: writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋™์•ˆ"]
        RS_WRITER["writer: RefMut guard"]
        subgraph RS_CELL["text: RefCell ๊ฐ’"]
            RS_STATE["borrow ์ƒํƒœ: ์“ฐ๊ธฐ ์ค‘"]
            RS_STRING["String ๊ฐ’: ํฌ์ธํ„ฐ, ๊ธธ์ด 7, capacity"]
        end
    end
    subgraph RS_HEAP["Heap"]
        RS_BYTES["UTF-8 ๋ฒ„ํผ: hi Rust"]
    end
    RS_WRITER -->|String ๊ฐ’ ๋นŒ๋ฆผ| RS_STRING
    RS_WRITER -->|borrow ์ƒํƒœ ์ถ”์ | RS_STATE
    RS_STRING -->|๋ฒ„ํผ ์†Œ์œ | RS_BYTES
  • String์˜ ์ €์žฅ ์œ„์น˜: ๊ด€๋ฆฌ ๊ฐ’์€ text ์•ˆ์— ํฌํ•จ๋˜๊ณ  ๋ฌธ์ž์—ด ๋ฐ”์ดํŠธ hi Rust๋Š” heap ๋ฒ„ํผ์— ์žˆ๋‹ค. RefCell ์•ˆ์— String์„ ๋‹ด๋Š”๋‹ค๊ณ  ๋ฌธ์ž์—ด ๋ฒ„ํผ๋ฅผ ์ƒˆ๋กœ ๋ณต์ œํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • guard์˜ ์ ‘๊ทผ ๋Œ€์ƒ: writer๋Š” RefCell ์•ˆ์˜ String ๊ฐ’์„ ๋นŒ๋ฆฐ๋‹ค. writer.push_str(" Rust")๋Š” ๊ทธ String์ด ์†Œ์œ ํ•œ ๋ฒ„ํผ์— ๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
RefCell<Vec<i32>>
use std::cell::RefCell;
 
fn main() {
    let values = RefCell::new(vec![10, 20]);
 
    {
        let mut writer = values.borrow_mut();
        writer.push(30);
        assert_eq!(writer.as_slice(), &[10, 20, 30]);
        // ๋„์‹ ์‹œ์ : writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
    }
 
    assert_eq!(values.borrow().as_slice(), &[10, 20, 30]);
}
flowchart TB
    subgraph RV_STACK["Stack: writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋™์•ˆ"]
        RV_WRITER["writer: RefMut guard"]
        subgraph RV_CELL["values: RefCell ๊ฐ’"]
            RV_STATE["borrow ์ƒํƒœ: ์“ฐ๊ธฐ ์ค‘"]
            RV_VEC["Vec ๊ฐ’: ํฌ์ธํ„ฐ, ๊ธธ์ด 3, capacity"]
        end
    end
    subgraph RV_HEAP["Heap"]
        RV_BUFFER["<table style='border-collapse:collapse;table-layout:fixed;width:240px'><tr><td colspan='3' style='border:none;padding:0 0 6px'>Vec ์›์†Œ ๋ฒ„ํผ</td></tr><tr><td style='border:1px solid currentColor;padding:8px 0'>10</td><td style='border:1px solid currentColor;padding:8px 0'>20</td><td style='border:1px solid currentColor;padding:8px 0'>30</td></tr><tr><td>[0]</td><td>[1]</td><td>[2]</td></tr></table>"]
    end
    RV_WRITER -->|Vec ๊ฐ’ ๋นŒ๋ฆผ| RV_VEC
    RV_WRITER -->|borrow ์ƒํƒœ ์ถ”์ | RV_STATE
    RV_VEC -->|๋ฒ„ํผ ์†Œ์œ | RV_BUFFER

RefCell ์ž์‹ ์ด ๋†“์ด๋Š” ์œ„์น˜๋Š” ๋ฐ”๊นฅ์— ๋‹ด๋Š” ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค.
๊ฐ™์€ RefCell<String>์„ Box๋‚˜ Rc ์•ˆ์— ๋‹ด์œผ๋ฉด borrow ์ƒํƒœ์™€ String ๊ด€๋ฆฌ ๊ฐ’๋„ ๊ทธ heap ํ• ๋‹น ์•ˆ์— ๋†“์ด๊ณ  ๋ฌธ์ž์—ด ๋ฒ„ํผ๋Š” ๋ณ„๋„ heap ํ• ๋‹น์œผ๋กœ ์œ ์ง€๋œ๋‹ค.


4. Rc์™€ RefCell์˜ ์กฐํ•ฉ

Rc์™€ RefCell: ์กฐํ•ฉ๊ณผ ์ˆ˜์ • ๋Œ€์ƒ

  • ๊ธฐ๋ณธ ์—ญํ• : Rc๋Š” ๊ฐ™์€ ๊ฐ’์˜ ๊ณต์œ  ์†Œ์œ ๊ถŒ์„, RefCell์€ ๋‚ด๋ถ€ ๊ฐ’์„ ๋นŒ๋ฆฌ๋Š” ์ ‘๊ทผ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
  • Rc<RefCell<T>>: ์—ฌ๋Ÿฌ Rc๊ฐ€ ๊ฐ™์€ RefCell๊ณผ ๊ทธ ์•ˆ์˜ T๋ฅผ ํ•จ๊ป˜ ์†Œ์œ ํ•œ๋‹ค. ๊ฐ ์†Œ์œ ์ž๋Š” guard๋ฅผ ์–ป์–ด ๊ฐ™์€ T๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • RefCell<Rc<T>>: RefCell ์•ˆ์˜ Rc๋ฅผ ๊ต์ฒดํ•ด ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์„ ๋ฐ”๊พผ๋‹ค.

4.1 ์ „ํˆฌยทํšŒ๋ณต ๊ธฐ๋Šฅ์˜ ํ”Œ๋ ˆ์ด์–ด ๊ณต์œ 

3.2์ ˆ์˜ combatยทhealing์€ local variable player๋ฅผ &RefCell<Player>๋กœ ๋นŒ๋ ธ์œผ๋ฏ€๋กœ ๋‘ ๊ธฐ๋Šฅ์ด ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ player๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ–ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” RefCell๊ณผ Player๋ฅผ Rc์˜ heap ํ• ๋‹น ์•ˆ์— ๋‹ด๊ณ  combatยทhealing์ด ๊ฐ์ž Rc<RefCell<Player>>๋ฅผ ์†Œ์œ ํ•œ๋‹ค. ๊ฐ ๊ธฐ๋Šฅ์ด ์ž๊ธฐ Rc๋ฅผ ๋ณด์œ ํ•˜๋Š” ๋™์•ˆ ๊ฐ™์€ ๊ฐ’์ด ์œ ์ง€๋˜๋ฏ€๋กœ combat์„ ๋จผ์ € dropํ•ด๋„ healing์€ Player๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹œ์  โ‘ ์€ ์ฒด๋ ฅ์„ 100์—์„œ 70์œผ๋กœ ๋ฐ”๊พผ ์งํ›„์ด๋ฉฐ ์“ฐ๊ธฐ borrow ์ค‘์—๋Š” ํšŒ๋ณต ๊ธฐ๋Šฅ์˜ ์ฝ๊ธฐ๋„ ๊ฑฐ๋ถ€๋œ๋‹ค.

use std::cell::RefCell;
use std::rc::Rc;
 
struct Player {
    hp: i32,
}
 
fn main() {
    let combat = Rc::new(RefCell::new(Player { hp: 100 }));
    let healing = Rc::clone(&combat);
 
    {
        let mut writer = combat.borrow_mut(); // RefMut<Player>
        writer.hp -= 30;
        assert!(healing.try_borrow().is_err());
        // ๋„์‹ ์‹œ์  โ‘ : strong count๋Š” 2์ด๊ณ  writer๊ฐ€ ์“ฐ๊ธฐ borrow๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
    }
 
    healing.borrow_mut().hp += 20;
    combat.borrow_mut().hp -= 10;
    drop(combat);
    // ๋„์‹ ์‹œ์  โ‘ก: combat์„ dropํ•˜๊ณ  healing๋งŒ ๋‚จ์€ ๋’ค
 
    assert_eq!(healing.borrow().hp, 80);
    assert_eq!(Rc::strong_count(&healing), 1);
}
flowchart TB
    subgraph RCF_STACK["Stack: โ‘  writer๊ฐ€ ์กด์žฌํ•˜๋Š” ๋™์•ˆ"]
        RCF_A["combat: Rc ํฌ์ธํ„ฐ"]
        RCF_B["healing: Rc ํฌ์ธํ„ฐ"]
        RCF_WRITER["writer: RefMut guard"]
    end
    subgraph RCF_HEAP["Heap์˜ ๊ณต์œ  ํ• ๋‹น ํ•˜๋‚˜"]
        RCF_DATA["strong 2 / RefCell / borrow: ์“ฐ๊ธฐ ์ค‘ / Player์˜ hp: 70"]
    end
    RCF_A -->|๊ณต์œ  ์†Œ์œ | RCF_DATA
    RCF_B -->|๊ณต์œ  ์†Œ์œ | RCF_DATA
    RCF_WRITER -->|RefCell ๋‚ด๋ถ€ Player๋ฅผ ๋นŒ๋ฆผ| RCF_DATA
  • ๊ณต์œ  ๋Œ€์ƒ: combatยทhealing์€ ๊ฐ™์€ RefCell๊ณผ ๊ทธ ์•ˆ์˜ Player๋ฅผ ์†Œ์œ 
  • ์ƒํƒœ์˜ ๊ตฌ๋ถ„: Rc::cloneยทRc์˜ drop์€ strong count๋ฅผ ๋ฐ”๊พธ๊ณ  guard์˜ ์ƒ์„ฑยทdrop์€ RefCell์˜ borrow ์ƒํƒœ๋ฅผ ๋ฐ”๊ฟˆ
  • ๋ฉ”์„œ๋“œ ํƒ์ƒ‰: combat.borrow_mut()์€ Rc์˜ dereference๋กœ ๋‚ด๋ถ€ RefCell์— ์ ‘๊ทผํ•œ ๋’ค RefCell::borrow_mut()์„ ํ˜ธ์ถœ

์‹œ์  โ‘ ์˜ ๊ณต์œ  ํ• ๋‹น ์•ˆ์—์„œ ํ•„๋“œ๊ฐ€ ํฌํ•จ๋˜๋Š” ๊ด€๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

flowchart TB
    subgraph RCF_ALLOCATION["์‹œ์  โ‘ : ๊ฐ™์€ Rc ํ• ๋‹น์˜ ๋‚ด๋ถ€ ํ™•๋Œ€"]
        RCF_COUNT["Rc ์นด์šดํ„ฐ: strong 2"]
        subgraph RCF_CELL["RefCell"]
            RCF_STATE["borrow ์ƒํƒœ: ์“ฐ๊ธฐ ์ค‘"]
            RCF_VALUE["Player ๊ฐ’ / hp: i32 = 70"]
        end
    end
  • RefCell๊ณผ Player๋Š” Rc์˜ heap ํ• ๋‹น ์•ˆ์— ํ•จ๊ป˜ ํฌํ•จ๋œ๋‹ค. wrapper๋ฅผ ํ•˜๋‚˜ ๋” ๊ฐ์ŒŒ๋‹ค๋Š” ์ด์œ ๋กœ heap ํ• ๋‹น์ด ํ•˜๋‚˜ ๋” ์ƒ๊ธฐ์ง€๋Š” ์•Š๋Š”๋‹ค.
  • writer๊ฐ€ drop๋˜๋ฉด ๋‹ค์‹œ ์ฝ๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ดํ›„ ํšŒ๋ณต๊ณผ ์ „ํˆฌ๋ฅผ ๊ฑฐ์ณ ์ฒด๋ ฅ์€ 80์ด ๋˜๊ณ  combat์„ dropํ•œ ๋’ค์—๋„ healing์ด ๊ทธ ๊ฐ’์„ ์†Œ์œ ํ•œ๋‹ค.
flowchart LR
    subgraph RCF_REMAINING_STACK["Stack: โ‘ก combat์„ dropํ•œ ๋’ค"]
        RCF_REMAINING_HEALING["healing: Rc ํฌ์ธํ„ฐ"]
    end
    subgraph RCF_REMAINING_HEAP["Heap: ๊ฐ™์€ ๊ณต์œ  ํ• ๋‹น"]
        RCF_REMAINING_DATA["strong 1 / RefCell / borrow: ๋นŒ๋ฆผ ์—†์Œ / Player์˜ hp: 80"]
    end
    RCF_REMAINING_HEALING -->|๊ณต์œ  ์†Œ์œ | RCF_REMAINING_DATA

4.2 wrapper ์ˆœ์„œ์™€ ์ˆ˜์ • ๋Œ€์ƒ

Rc<RefCell<T>>๋Š” ์—ฌ๋Ÿฌ ์†Œ์œ ์ž๊ฐ€ ๊ฐ™์€ T๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์กฐํ•ฉ์ด๋‹ค. ์ˆœ์„œ๋ฅผ ๋ฐ”๊พผ RefCell<Rc<T>>๋Š” ๋‚ด๋ถ€ Rc๋ฅผ ๊ต์ฒดํ•ด ๊ณต์œ ํ•  ๋Œ€์ƒ์„ ๋ฐ”๊พธ๋Š” ๋ฐ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด single thread์—์„œ ์—ฌ๋Ÿฌ ์ฝœ๋ฐฑ์ด ๊ฐ™์€ ์„ค์ • ๊ด€๋ฆฌ ๊ฐ์ฒด๋ฅผ ๊ณต์œ  ์ฐธ์กฐ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•˜์ž. ๊ฐ ์ž‘์—…์€ ์‹œ์ž‘ํ•  ๋•Œ Rc<Config>๋ฅผ ๋ณต์ œํ•ด ์„ค์ • ์Šค๋ƒ…์ƒท์„ ๋ณด๊ด€ํ•œ๋‹ค. ์„ค์ •์ด ๊ฐฑ์‹ ๋˜๋ฉด ์ดํ›„ ์ž‘์—…์—๋Š” ์ƒˆ ์„ค์ •์„ ์ œ๊ณตํ•˜๋˜ ๊ธฐ์กด ์ž‘์—…์€ ์ฒ˜์Œ ๋ฐ›์€ ์„ค์ •์œผ๋กœ ๊ณ„์† ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

๊ด€๋ฆฌ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ &self๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ตฌ์กฐ์—์„œ๋Š” ์ผ๋ฐ˜ Rc ํ•„๋“œ์— ์ƒˆ Rc๋ฅผ ๋Œ€์ž…ํ•  ์ˆ˜ ์—†๋‹ค. ํ•„๋“œ๋ฅผ RefCell<Rc<Config>>๋กœ ๋‘๋ฉด ๊ณต์œ  ์ฐธ์กฐ๋กœ๋„ ํ˜„์žฌ ์„ค์ •์˜ Rc๋ฅผ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ์กด ์ž‘์—…์ด ๋ณด์œ ํ•œ Rc๋Š” ์ด์ „ Config๋ฅผ ๊ณ„์† ์œ ์ง€ํ•œ๋‹ค. ์ž‘์—…์— Rc๋ฅผ ๋ณต์ œํ•ด ๋„˜๊ธด ๋’ค์—๋Š” RefCell์˜ ์ฝ๊ธฐ guard๋ฅผ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋Š” Rc์˜ ๊ต์ฒด์™€ ๊ธฐ์กด ๊ฐ’์˜ ์œ ์ง€๋ฅผ i32๋กœ ๋‹จ์ˆœํ™”ํ•œ ์˜ˆ์ œ๋‹ค.

use std::cell::RefCell;
use std::rc::Rc;
 
fn main() {
    let original = Rc::new(10);
    let slot: RefCell<Rc<i32>> = RefCell::new(Rc::clone(&original));
    // ๋„์‹ ์‹œ์  โ‘ : original๊ณผ slot ์•ˆ์˜ Rc๊ฐ€ ๊ฐ™์€ 10์„ ์†Œ์œ ํ•œ๋‹ค.
 
    let previous: Rc<i32> = slot.replace(Rc::new(20));
    // ๋„์‹ ์‹œ์  โ‘ก: slot์€ ์ƒˆ 20์„, original๊ณผ previous๋Š” ๊ธฐ์กด 10์„ ์†Œ์œ ํ•œ๋‹ค.
 
    assert_eq!(**slot.borrow(), 20);
    assert_eq!(*original, 10);
    assert_eq!(*previous, 10);
    assert!(Rc::ptr_eq(&original, &previous));
}

์‹œ์  โ‘ ์—์„œ๋Š” original๊ณผ slot ์•ˆ์˜ Rc๊ฐ€ ๊ฐ™์€ heap ํ• ๋‹น์„ ์†Œ์œ ํ•œ๋‹ค.

flowchart TB
    subgraph SLOT_BEFORE_STACK["Stack: โ‘  Rc๋ฅผ ๊ต์ฒดํ•˜๊ธฐ ์ „"]
        SLOT_BEFORE_ORIGINAL["original: Rc ํฌ์ธํ„ฐ"]
        SLOT_BEFORE_CELL["slot: RefCell / borrow: ๋นŒ๋ฆผ ์—†์Œ / ๋‚ด๋ถ€ Rc ํฌ์ธํ„ฐ"]
    end
    subgraph SLOT_BEFORE_HEAP["Heap: Rc ํ• ๋‹น ํ•˜๋‚˜"]
        SLOT_BEFORE_DATA["strong: 2 / i32 ๊ฐ’: 10"]
    end
    SLOT_BEFORE_ORIGINAL -->|๊ณต์œ  ์†Œ์œ | SLOT_BEFORE_DATA
    SLOT_BEFORE_CELL -->|๋‚ด๋ถ€ Rc๋กœ ๊ณต์œ  ์†Œ์œ | SLOT_BEFORE_DATA
  • ์ €์žฅ ์œ„์น˜: stack์˜ slot ์•ˆ์—๋Š” borrow ์ƒํƒœ์™€ Rc ํฌ์ธํ„ฐ๊ฐ€ ์žˆ๊ณ  i32 ๊ฐ’๊ณผ ์นด์šดํ„ฐ๋Š” Rc์˜ heap ํ• ๋‹น์— ์กด์žฌ

์‹œ์  โ‘ก์—์„œ๋Š” slot ์•ˆ์˜ Rc๊ฐ€ ์ƒˆ ํ• ๋‹น์˜ 20์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ๊ธฐ์กด Rc๋Š” previous๋กœ ์ด๋™ํ•œ๋‹ค.

flowchart TB
    subgraph SLOT_AFTER_STACK["Stack: โ‘ก Rc๋ฅผ ๊ต์ฒดํ•œ ๋’ค"]
        SLOT_AFTER_ORIGINAL["original: Rc ํฌ์ธํ„ฐ"]
        SLOT_AFTER_CELL["slot: RefCell / borrow: ๋นŒ๋ฆผ ์—†์Œ / ๋‚ด๋ถ€ Rc ํฌ์ธํ„ฐ"]
        SLOT_AFTER_PREVIOUS["previous: ๊ต์ฒด ์ „์˜ Rc ํฌ์ธํ„ฐ"]
    end
    subgraph SLOT_AFTER_HEAP["Heap: ๊ธฐ์กด ํ• ๋‹น๊ณผ ์ƒˆ ํ• ๋‹น"]
        SLOT_AFTER_OLD["strong: 2 / i32 ๊ฐ’: 10"]
        SLOT_AFTER_NEW["strong: 1 / i32 ๊ฐ’: 20"]
    end
    SLOT_AFTER_ORIGINAL -->|๊ณต์œ  ์†Œ์œ | SLOT_AFTER_OLD
    SLOT_AFTER_PREVIOUS -->|๊ณต์œ  ์†Œ์œ | SLOT_AFTER_OLD
    SLOT_AFTER_CELL -->|๋‚ด๋ถ€ Rc๋กœ ๊ณต์œ  ์†Œ์œ | SLOT_AFTER_NEW
  • ๊ต์ฒด ๋Œ€์ƒ
    • RefCell::replace๋Š” ๋‚ด๋ถ€ ๊ฐ’์„ ์ƒˆ ๊ฐ’์œผ๋กœ ๋ฐ”๊พธ๊ณ  ์ด์ „ ๊ฐ’์„ ๋ฐ˜ํ™˜ (์—ฌ๊ธฐ์„œ๋Š” Rc<i32>๋ฅผ ๊ต์ฒดํ–ˆ์œผ๋ฏ€๋กœ ๋ฐ˜ํ™˜๊ฐ’๋„ Rc<i32>)
    • ๋‚ด๋ถ€ ๊ฐ’์˜ borrow๊ฐ€ ๋‚จ์•„ ์žˆ์œผ๋ฉด panic
  • ๊ธฐ์กด ๊ฐ’์˜ ์ˆ˜๋ช…
    • 10์€ ์ˆ˜์ •๋˜์ง€ ์•Š์œผ๋ฉฐ original๊ณผ previous๊ฐ€ ๊ณ„์† ์†Œ์œ 
    • slot์˜ ๊ต์ฒด๊ฐ€ ๋‹ค๋ฅธ Rc์˜ ๋Œ€์ƒ์„ ํ•จ๊ป˜ ๋ฐ”๊พธ์ง€๋Š” ์•Š์Œ

5. ํƒ€์ž… ์„ ํƒ

5.1 ์†Œ์œ ๊ถŒ๊ณผ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋น„๊ต

ํƒ€์ž…๊ณต์œ  ์†Œ์œ ๊ถŒ๋‚ด๋ถ€ T์˜ ์ €์žฅ ์œ„์น˜๋‚ด๋ถ€ ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ๋กœ๊ณต์œ  ๋ฒ”์œ„
Rc<T>์ œ๊ณตRc์˜ ๊ณต์œ  heap ํ• ๋‹น ์•ˆget_mutยทmake_mut ๋˜๋Š” T์˜ ๋‚ด๋ถ€ ๊ฐ€๋ณ€์„ฑ API๊ฐ™์€ thread
RefCell<T>์ œ๊ณต ์•ˆ ํ•จRefCell ์ž์‹ ์˜ ํ•„๋“œborrow_mutยทtry_borrow_mut์˜ guard๊ฐ™์€ thread์—์„œ์˜ ๊ณต์œ  ์ฐธ์กฐ ์ ‘๊ทผ
Rc<RefCell<T>>์ œ๊ณตRc ํ• ๋‹น ์•ˆ์˜ RefCell ํ•„๋“œRefCell์˜ guard๊ฐ™์€ thread
RefCell<Rc<T>>Rc๊ฐ€ ์ œ๊ณตRc์˜ ๊ณต์œ  heap ํ• ๋‹น ์•ˆguardยทreplace๋กœ ๋‚ด๋ถ€ Rc ๊ต์ฒด. T ์ˆ˜์ •์€ Rc์˜ ๊ทœ์น™์„ ๋”ฐ๋ฆ„๊ฐ™์€ thread

5.2 ์ƒํ™ฉ๋ณ„ ์กฐํ•ฉ

ํ•„์š”ํ•œ ๋™์ž‘์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…
ํ•œ ์†Œ์œ ์ž๊ฐ€ ๊ฐ’์„ ์ˆ˜์ •ํ•˜๊ณ  ๋ฐฐํƒ€์ ์ธ ์ ‘๊ทผ๋„ ํ™•๋ณด ๊ฐ€๋Šฅ์ผ๋ฐ˜ ๊ฐ’๊ณผ &mut T
๊ฐ™์€ thread์˜ ์—ฌ๋Ÿฌ ๊ฐ์ฒด๊ฐ€ ๊ฐ’์˜ ์ˆ˜๋ช…์„ ํ•จ๊ป˜ ์œ ์ง€Rc<T>
๊ณต์œ  ์ฐธ์กฐ๋กœ ์ ‘๊ทผํ•˜๋ฉด์„œ ์‹คํ–‰ ์ค‘ ๊ฒ€์‚ฌ๋กœ ๋‚ด๋ถ€ ๊ฐ’ ์ˆ˜์ •RefCell<T>
๊ฐ™์€ thread์˜ ์—ฌ๋Ÿฌ ์†Œ์œ ์ž๊ฐ€ ๊ฐ™์€ ๊ฐ’ ์ˆ˜์ •Rc<RefCell<T>>
๊ณต์œ  ์ฐธ์กฐ๋กœ ํ˜„์žฌ Rc๋ฅผ ๊ต์ฒดํ•˜๊ณ  ๊ธฐ์กด ์†Œ์œ ์ž์˜ ๊ฐ’์€ ์œ ์ง€RefCell<Rc<T>>

์†Œ์œ ๊ถŒ์„ ์ด๋ฏธ ๋นŒ๋ ค ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๋ผ๋ฉด &Tยท&mut T๋งŒ์œผ๋กœ๋„ ํ•„์š”ํ•œ ์ ‘๊ทผ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ™์€ thread ์•ˆ์—์„œ๋Š” ๊ณต์œ  ์†Œ์œ ๊ถŒ์ด ํ•„์š”ํ•œ์ง€์™€ ๊ณต์œ  ์ฐธ์กฐ๋กœ ๋‚ด๋ถ€ ๊ฐ’์„ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๊ฐ๊ฐ ๊ฒฐ์ •ํ•˜๋ฉด wrapper์˜ ์—ญํ• ์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๋Ÿฌ thread๊ฐ€ ๊ฐ™์€ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์˜ Arc์™€ Mutex๋Š” ๋ณ„๋„ ๊ธ€์—์„œ ๋‹ค๋ฃฌ๋‹ค.

Footnotes

  1. ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ์น˜๋ฅผ ์„ค๋ช…ํ•  ๋•Œ ์“ฐ๋Š” ํ‘œํ˜„์ด๋‹ค. SmallVec ๋ฌธ์„œ์—์„œ๋„ ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€์— ์›์†Œ๋ฅผ ์ง์ ‘ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์„ inline์œผ๋กœ ํ‘œํ˜„ํ•œ๋‹ค. โ†ฉ

  2. ์˜ˆ๋ฅผ ๋“ค์–ด ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ์˜ ํด๋” ํŠธ๋ฆฌ์—์„œ ๋ฌธ์„œ ๋…ธ๋“œ๊ฐ€ ์ž์‹ ์‚ฌ์ง„์„ Rc๋กœ ๋ณด์œ ํ•˜๊ณ  ์‚ฌ์ง„๋„ ์ƒ์œ„ ํด๋” ํƒ์ƒ‰์„ ์œ„ํ•ด ๋ฌธ์„œ๋ฅผ Rc๋กœ ๋ณด์œ ํ•˜๋Š” ๊ฒฝ์šฐ๋‹ค. ์ด๋Ÿฐ ์–‘๋ฐฉํ–ฅ ์†Œ์œ  ๊ด€๊ณ„์—์„œ๋Š” ์™ธ๋ถ€ Rc๋ฅผ ๋ชจ๋‘ dropํ•ด๋„ ๋‘ ๋…ธ๋“œ๊ฐ€ ์„œ๋กœ๋ฅผ ์†Œ์œ ํ•ด strong count๊ฐ€ ๊ฐ๊ฐ 1๋กœ ๋‚จ๋Š”๋‹ค. โ†ฉ