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 typeT, 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 ํ ๋น์ด ์๊ธด๋ค.
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 variablenumber์๋ ๊ทธ ํ ๋น์ ๊ฐ๋ฆฌํค๋ 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๊ฐ ์ถ๋ก ํ๋ค.
๊ตฌํ: guard๊ฐ ๋ด๋ ์ ๋ณด
ํ์ฌ ํ์ ์ ์์์ ์ฃผ์๊ณผ ์์ฑ์ ์๋ตํ ๋ชจ์ต์ด๋ค.
pub struct Ref<'b, T: ?Sized + 'b> { value: NonNull<T>, borrow: BorrowRef<'b>, } pub struct RefMut<'b, T: ?Sized + 'b> { value: NonNull<T>, borrow: BorrowRefMut<'b>, marker: PhantomData<&'b mut T>, }
value: ๋ด๋ถ T์ ์ฃผ์๋ฅผ ๋ด๋ ํฌ์ธํฐ๋ค. guard๋ ์ด ํฌ์ธํฐ๋ก ๊ธฐ์กด ๊ฐ์ ์ ๊ทผํ๋ค.borrow: RefCell์ borrow ์นด์ดํฐ๋ฅผ ์ฐธ์กฐํ๋ ์ถ์ ๊ฐ์ฒด๋ค. guard๊ฐ drop๋๋ฉด ์ด ๊ฐ์ฒด๋ drop๋๋ฉด์ ์ฝ๊ธฐ borrow๋ ์นด์ดํฐ๋ฅผ1์ค์ด๊ณ , ์ผ๋ฐ์ ์ธ ์ฐ๊ธฐ borrow๋-1์์0์ผ๋ก ๋๋๋ฆฐ๋ค.marker: RefMut์ lifetime๊ณผ ๊ฐ๋ณ ์ฐธ์กฐ์ ๊ดํ ํ์ ์ ๋ณด๋ฅผ compiler์ ์ ๋ฌํ๋ค.PhantomData์์ฒด๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ง ์๋๋ค.
ํ์ฌ ๊ตฌํ์ isize ์นด์ดํฐ๋ก borrow ์ข
๋ฅ์ ๊ฐ์๋ฅผ ํจ๊ป ๊ธฐ๋กํ๋ค.
0์ ๋น๋ฆผ ์์- ์์
n์ ์ฝ๊ธฐ guardn๊ฐ - ์์๋ ์ฐ๊ธฐ 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 + 1 | n < 0์ด๋ฉด Err |
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> | ์ฐ๊ธฐ ์ฑ๊ณต ์ 0 โ -1 | n != 0์ด๋ฉด Err |
pub fn replace(&self, t: T) -> T | ๋ด๋ถ T ๊ต์ฒดยท๊ธฐ์กด T์ ์์ ๊ถ ๋ฐํ, ํธ์ถ ๋ค ์นด์ดํฐ 0 | ๋ค๋ฅธ borrow๊ฐ ์๋ n != 0์ด๋ฉด panic |
pub fn get_mut(&mut self) -> &mut T | runtime borrow ๊ฒ์ฌ ์์ด ๋ด๋ถ ๊ฐ ์ ๊ทผ | &mut self๋ก ๋ฐฐํ ์ ๊ทผ ํ๋ณด |
pub const fn into_inner(self) -> T | RefCell์ ์๋นํ๊ณ T์ ์์ ๊ถ ๋ฐํ | self ์์ ๊ถ ํ์ |
์คํจํ borrow ์์ฒญ์ ์นด์ดํฐ๋ฅผ ๋ฐ๊พธ์ง ์๋๋ค. ์ฌ๋ฌ ์ฝ๊ธฐ borrow๋ฅผ ํจ๊ป ์ ์งํ๊ฑฐ๋ ์ฐ๊ธฐ borrow ํ๋๋ฅผ ์ ์งํ ์ ์์ผ๋ฉฐ ์ฝ๊ธฐ์ ์ฐ๊ธฐ๋ ๊ฒน์น ์ ์๋ค.
- ์ถฉ๋ ์ฒ๋ฆฌ์ ์ ํ
borrow()ยทborrow_mut()์ ์ถฉ๋์ ํ๋ก๊ทธ๋จ ์ค๋ฅ๋ก ์ทจ๊ธํด panic- ์คํจ ์ ๋ค๋ฅธ ์์
์ ํ๊ฑฐ๋ ๋์ค์ ๋ค์ ์๋ํ๋ ค๋ฉด
try_borrow()ยทtry_borrow_mut()์Result๋ฅผmatch๋if let์ผ๋ก ์ฒ๋ฆฌ
- unwrap์ ๋์
borrow()์try_borrow().unwrap()์ ์ฑ๊ณตํ๋ฉด ๊ฐ์ ์ข ๋ฅ์ ์ฝ๊ธฐ guard๋ฅผ ์ป๊ณ ์ถฉ๋ํ๋ฉด ๋ ๋ค panicborrow()๋ 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ยทRefMutguard๋ ๋ง์ง๋ง ์ฌ์ฉ๊ณผ ๋ณ๊ฐ๋ก 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 variablecell์์ ์๋ค.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
- RefCell::replace๋ ๋ด๋ถ ๊ฐ์ ์ ๊ฐ์ผ๋ก ๋ฐ๊พธ๊ณ ์ด์ ๊ฐ์ ๋ฐํ (์ฌ๊ธฐ์๋
- ๊ธฐ์กด ๊ฐ์ ์๋ช
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
-
๋ฉ๋ชจ๋ฆฌ ๋ฐฐ์น๋ฅผ ์ค๋ช ํ ๋ ์ฐ๋ ํํ์ด๋ค. SmallVec ๋ฌธ์์์๋ ๊ตฌ์กฐ์ฒด ๋ด๋ถ์ ์์๋ฅผ ์ง์ ์ ์ฅํ๋ ๋ฐฉ์์
inline์ผ๋ก ํํํ๋ค. โฉ -
์๋ฅผ ๋ค์ด ํ์ผ ํ์๊ธฐ์ ํด๋ ํธ๋ฆฌ์์
๋ฌธ์๋ ธ๋๊ฐ ์์์ฌ์ง์Rc๋ก ๋ณด์ ํ๊ณ์ฌ์ง๋ ์์ ํด๋ ํ์์ ์ํด๋ฌธ์๋ฅผRc๋ก ๋ณด์ ํ๋ ๊ฒฝ์ฐ๋ค. ์ด๋ฐ ์๋ฐฉํฅ ์์ ๊ด๊ณ์์๋ ์ธ๋ถ Rc๋ฅผ ๋ชจ๋ dropํด๋ ๋ ๋ ธ๋๊ฐ ์๋ก๋ฅผ ์์ ํด strong count๊ฐ ๊ฐ๊ฐ1๋ก ๋จ๋๋ค. โฉ