Rust Memory Master
Rust์ ๊ฐ์ฅ ์ด๋ ค์ด ๊ฐ๋ ๋ค์ ์๊ฐ์ ์ผ๋ก ํ์ตํ์ธ์.
Rust์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ์์คํ (Ownership, Borrowing, Lifetimes)์ ๊ฐ๋ ฅํ์ง๋ง ํ์ต ๊ณก์ ์ด ๊ฐํ๋ฆ ๋๋ค. ์ด ํ๋ซํผ์ ๋ณต์กํ ๊ฐ๋ ์ ์ง๊ด์ ์ธ ์๊ฐํ์ ์ค์ฉ์ ์ธ ์์ ๋ก ์ฝ๊ฒ ์ดํดํ ์ ์๋๋ก ๋์ต๋๋ค.
ํ์ต ๊ฒฝ๋ก
- ์๊ฐํ ๋๊ตฌ - Ownership, Borrowing, Lifetimes ์์
- Primitives - Copy trait๊ณผ ์์ ํ์
- ํด์ฆ - ํ์ต ๋ด์ฉ ํ์ธ
- ์ด๋ณด ์ด๋ ค์ - ํํ ์ค์์ ํด๊ฒฐ์ฑ
ํน์ง
- ์ธํฐ๋ํฐ๋ธ ์๊ฐํ: Canvas ๊ธฐ๋ฐ ์ค์๊ฐ ๋ฉ๋ชจ๋ฆฌ ๋ค์ด์ด๊ทธ๋จ
- ์ค์ฉ์ ์ธ ์์ : ์ค์ ์ฝ๋์ ํจ๊ปํ๋ ํ์ต
- ์ฆ์ ํผ๋๋ฐฑ: ํด์ฆ๋ก ํ์ต ๋ด์ฉ ํ์ธ
- ๋ฐ์ํ ๋์์ธ: ๋ชจ๋ฐ์ผ๊ณผ ๋ฐ์คํฌํฑ ๋ชจ๋ ์ง์
์์ํ๊ธฐ: ์ ํญ์์ ์ํ๋ ์ฃผ์ ๋ฅผ ์ ํํ๊ฑฐ๋ ํ์ต ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ผ ์งํํ์ธ์.
๐จ ์ธํฐ๋ํฐ๋ธ ์๊ฐํ ๋๊ตฌ
Ownership, Borrowing, Lifetimes๋ฅผ ์๊ฐ์ ์ผ๋ก ํ์ตํ์ธ์!
๐ฑ ๋ชจ๋ฐ์ผ์์ ๋จ๊ณ๋ณ๋ก ํ์ธํ์ธ์!
์์ ์ ํ
1๏ธโฃ Ownership ์์
2๏ธโฃ Borrowing ์์
3๏ธโฃ Lifetimes ์์
4๏ธโฃ ์ค๋งํธ ํฌ์ธํฐ (WASM ์๋ฎฌ๋ ์ด์ )
5๏ธโฃ ์ฌ๋ผ์ด์ค & Cow
๐ ํต์ฌ ๊ฐ๋
๐ฐ Ownership = ๋ง๋ฒ ๋์๊ด
- ๊ฐ ์ฑ ์ ํ ๋ช ์ ์ฃผ์ธ๋ง ์์
- ์ฃผ์ธ์ด ๋์๊ด์ ๋๊ฐ๋ฉด ์ฑ ์ฌ๋ผ์ง
- ๋น๋ ค์ค ์๋ ์์ง๋ง ์์ ๊ถ์ ์์
๐ Borrowing = ์ฑ ๋น๋ฆฌ๊ธฐ
- ์ฌ๋ฌ ์ฌ๋์ด ๋์์ ์ฝ๊ธฐ ๊ฐ๋ฅ (&T)
- ํ ๋ช ๋ง ์์ ๊ฐ๋ฅ (&mut T)
- ์ฝ๋ ์ค์๋ ์์ ๋ถ๊ฐ
โณ Lifetimes = ๋์ฌ ๊ธฐ๊ฐ
- ๊ฐ ์ฐธ์กฐ๋ ์ ํจ ๊ธฐ๊ฐ์ด ์์
- ๊ฐ์ฅ ์งง์ ๊ธฐ๊ฐ์ด ์ ์ฉ๋จ
- ์ปดํ์ผ๋ฌ๊ฐ ์๋ ์ถ๋ก
๐ฆ Primitives & Copy Trait
์์ ํ์ ๊ณผ Copy trait์ ์ดํดํ์ธ์!
์์ ์ ํ
1๏ธโฃ Copy Trait
์์ ํ์ ์ Copy ๋ฉ๋๋ค!
let x = 5;
let y = x; // Copy!
println!("{}", x); // โ
OK
2๏ธโฃ Move vs Copy
Copy์ Move์ ์ฐจ์ด๋ฅผ ๋น๊ตํด๋ณด์ธ์!
// Copy (i32)
let x = 5;
let y = x; // โ
๋ ๋ค ์ ํจ
// Move (String)
let s1 = String::from("Hello");
let s2 = s1; // โ ๏ธ s1 ๋ฌดํจํ
3๏ธโฃ ๋ชจ๋ ์์ ํ์
Rust์ ๋ชจ๋ ์์ ํ์ ์ ๋ง๋๋ณด์ธ์!
4๏ธโฃ Stack vs Heap
์์ ํ์ ์ Stack์, ์ปฌ๋ ์ ์ Heap์ ์ ์ฅ๋ฉ๋๋ค!
๐ Primitives ํต์ฌ ์ ๋ฆฌ
๐ Copy Trait = ๋ณต์ฌ๊ธฐ
- ๐ ์๋ณธ์ ๊ทธ๋๋ก ๋ณต์ฌ
- โ ๋ณต์ฌ๋ณธ๊ณผ ์๋ณธ ๋ชจ๋ ์ ํจ
- โก ๋งค์ฐ ๋น ๋ฅธ ๋นํธ ๋ณต์ฌ
- ๐พ Stack์๋ง ์ ์ฅ
๐ฆ ์์ ํ์ ๋ชฉ๋ก
- ์ ์: i8, i16, i32, i64, i128, isize
- ์ ์: u8, u16, u32, u64, u128, usize
- ๋ถ๋์์์ : f32, f64
- ๋ถ๋ฆฌ์ธ: bool (true/false)
- ๋ฌธ์: char (์ ๋์ฝ๋)
- ํํ: (T1, T2, ...)
๐ ์ฑ๋ฅ ํ
- โ ๊ฐ๋ฅํ ์์ ํ์ ์ฌ์ฉ: ๋ ๋น ๋ฆ
- โ ๋ถํ์ํ String ์ฌ์ฉ: &str์ด ๋ ๋น ๋ฆ
- ๐ก Stack์ด Heap๋ณด๋ค 10-100๋ฐฐ ๋น ๋ฆ
๐ ํด์ฆ ์์คํ
Rust ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๊ฐ๋ ์ ํด์ฆ๋ก ํ์ธํด๋ณด์ธ์!
๐ฏ Rust ํ์ต ํด์ฆ
30๋ฌธ์ , 3 ๋ ๋ฒจ๋ก ์ ์ง์ ํ์ต
๐ ์ด์ ์ง๋
๐ก ๋น์
๐ Level 1 ์๋ฃ!
๐ ์์ธ ๊ฒฐ๊ณผ
๐ฐ ์ด๋ณด ๊ฐ๋ฐ์๊ฐ ๊ฒช๋ ์ด๋ ค์
Rust ์ด๋ณด ๊ฐ๋ฐ์๋ค์ด ๊ฐ์ฅ ๋ง์ด ๊ฒช๋ 7๊ฐ์ง ์ด๋ ค์์ ์๊ฐํํ๊ณ , ํด๊ฒฐ์ฑ ์ ์ ์ํฉ๋๋ค!
1๏ธโฃ "์ use of moved value ์๋ฌ๊ฐ ๋๋์?"
โ ํํ ์ค์
let s1 = String::from("Hello");
let s2 = s1;
println!("{}", s1); // โ Error!
โ ํด๊ฒฐ์ฑ
let s1 = String::from("Hello");
let s2 = s1.clone();
println!("{}", s1); // โ
OK
2๏ธโฃ "์ cannot borrow as mutable ์๋ฌ๊ฐ ๋๋์?"
โ ํํ ์ค์
let s = String::from("Hello");
let r1 = &s;
let r2 = &mut s; // โ Error!
โ ํด๊ฒฐ์ฑ
let mut s = String::from("Hello");
let r1 = &s;
drop(r1);
let r2 = &mut s; // โ
OK
3๏ธโฃ "์๋ช ์ ๋ํ ์ด์ ('a)์ด ๋ญ๊ฐ์?"
โ ์๋ฌ
fn longest(x: &str, y: &str) -> &str {
// โ Missing lifetime
if x.len() > y.len() { x } else { y }
}
โ ํด๊ฒฐ์ฑ
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
// โ
Lifetime ๋ช
์
if x.len() > y.len() { x } else { y }
}
📖 Reference Guide
📦 Ownership
Core📊 ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ธ
์์ ์(Owner) ํ ๋ฉ๋ชจ๋ฆฌ(Heap) ┌──────────────┐ ┌──────────────────┐ │ s1 │ │ "Hello" │ │ ptr ─────────┤─▶│ len: 5 │ │ len: 5 │ │ cap: 5 │ │ cap: 5 │ └──────────────────┘ └──────────────┘ let s2 = s1; // Move! s1 ๋ฌดํจํ ┌──────────────┐ ┌──────────────────┐ │ s1 (๋ฌดํจ) ❌ │ │ "Hello" │ │ s2 │ │ (๋์ผ ๋ฉ๋ชจ๋ฆฌ) │ │ ptr ─────────┤─▶│ │ └──────────────┘ └──────────────────┘
💻 ํต์ฌ ์ฝ๋
// 1. ์์ ๊ถ ์ด๋ (Move)
let s1 = String::from("hello");
let s2 = s1; // s1์ ์์ ๊ถ์ด s2๋ก ์ด๋
// println!("{}", s1); // ❌ E0382: use of moved value
// 2. Clone์ผ๋ก ๊น์ ๋ณต์ฌ
let s3 = s2.clone(); // ✓ ๋ ๋ค ์ ํจ
println!("{} {}", s2, s3);
// 3. Copy trait (์์ ํ์
- Stack only)
let x = 5;
let y = x; // ✓ Copy! x๋ ์ฌ์ ํ ์ ํจ
println!("{} {}", x, y);
🚨 ๊ด๋ จ ์ปดํ์ผ๋ฌ ์๋ฌ
์์ ๊ถ์ด ์ด๋๋ ๋ณ์๋ฅผ ๋ค์ ์ฌ์ฉํ๋ ค ํ ๋ ๋ฐ์.
error[E0382]: borrow of moved value: `s1`
--> src/main.rs:3:20
|
2 | let s2 = s1;
| -- value moved here
3 | println!("{}", s1);
| ^^ value borrowed here after move
🤖 AI Context Block
# Rust Concept: Ownership
## Rules
1. Each value has exactly one owner
2. When owner goes out of scope, value is dropped
3. Ownership can be transferred (moved) but not shared
## Code Examples
```rust
// Move semantics
let s1 = String::from("hello");
let s2 = s1; // s1 is now invalid (moved)
// Clone for deep copy
let s3 = s2.clone(); // Both s2 and s3 are valid
// Copy types (stack-only primitives)
let x: i32 = 5;
let y = x; // Copy! Both valid (i32 implements Copy)
```
## Compiler Errors
- E0382: use of moved value (accessing s1 after move to s2)
## Common Mistakes
- Confusing Move with Copy: String moves, i32 copies
- Trying to use value after passing to function (implicit move)
- Solution: use .clone() or pass &reference instead
## Related Concepts
Borrowing, Lifetimes, Drop trait, Copy trait
📚 Borrowing
Core📊 ์ฐธ์กฐ ๊ท์น ์๊ฐํ
✓ ํ์ฉ: ๋ถ๋ณ ์ฐธ์กฐ ์ฌ๋ฌ ๊ฐ
let s = String::from("hello");
let r1 = &s; // โโ ๋์ ์กด์ฌ
let r2 = &s; // โโ ๊ฐ๋ฅ
❌ ๊ธ์ง: ๋ถ๋ณ + ๊ฐ๋ณ ๋์
let r1 = &s; // ๋ถ๋ณ
let r2 = &mut s; // ❌ E0502
✓ ํ์ฉ: ์ค์ฝํ ๋ถ๋ฆฌ (NLL)
{
let r1 = &s; // r1 ์ฌ๊ธฐ์ ๋
}
let r2 = &mut s; // ✓ ์ด์ ๊ฐ๋ฅ
💻 ํต์ฌ ์ฝ๋
// ๋ถ๋ณ ์ฐธ์กฐ (Immutable Reference)
fn calculate_length(s: &String) -> usize {
s.len() // ์ฝ๊ธฐ๋ง ๊ฐ๋ฅ
}
let s = String::from("hello");
let len = calculate_length(&s); // s๋ ์ฌ์ ํ ์ ํจ
// ๊ฐ๋ณ ์ฐธ์กฐ (Mutable Reference)
fn change(s: &mut String) {
s.push_str(" world");
}
let mut s = String::from("hello");
change(&mut s); // ✓ s๋ ์ฌ์ ํ ์์ ๊ถ ์ ์ง
🚨 ๊ด๋ จ ์ปดํ์ผ๋ฌ ์๋ฌ
๋ถ๋ณ ์ฐธ์กฐ๊ฐ ์ด์์๋ ๋์ ๊ฐ๋ณ ์ฐธ์กฐ๋ฅผ ๋ง๋ค๋ ค ํ ๋ ๋ฐ์.
๊ฐ๋ณ ์ฐธ์กฐ๋ฅผ ๋์์ ๋ ๊ฐ ๋ง๋ค๋ ค ํ ๋ ๋ฐ์.
์ฐธ์กฐ๊ฐ ์ด์์๋ ๋์ ์์ ๊ถ์ ์ด๋ํ๋ ค ํ ๋ ๋ฐ์.
🤖 AI Context Block
# Rust Concept: Borrowing
## Rules
1. At any time: either ONE &mut T OR any number of &T โ never both
2. References must always be valid (no dangling references)
3. NLL (Non-Lexical Lifetimes): borrow ends at last use, not scope end
## Code Examples
```rust
// Immutable reference - multiple allowed
let s = String::from("hello");
let r1 = &s;
let r2 = &s; // Both valid simultaneously
// Mutable reference - exclusive
let mut s = String::from("hello");
let r = &mut s;
r.push_str(" world"); // One mutable ref allowed
// NLL: borrow ends at last use
let mut s = String::from("hello");
let r1 = &s;
println!("{}", r1); // r1's last use
let r2 = &mut s; // r1 is already gone (NLL)
```
## Compiler Errors
- E0502: cannot borrow as mutable because also borrowed as immutable
- E0499: cannot borrow as mutable more than once at a time
- E0505: cannot move out of variable because it is borrowed
## Common Mistakes
- "Drop or scope-close the immutable ref before creating mutable"
- Forgetting NLL: references can end before scope closes
## Related Concepts
Ownership, Lifetimes, Interior Mutability (RefCell)
⏳ Lifetimes
Core📊 ์๋ช ์๊ฐํ
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str 'a = min(lifetime(x), lifetime(y)) ํ์๋ผ์ธ: x: โโโโโโโโโโโโโโโโโโโโโโโโโโโโ (๊ธธ๋ค) y: โโโโโโโโโโโโ (์งง๋ค) 'a: โโโโโโโโโโโโ (y๋ฅผ ๋ฐ๋ผ๊ฐ) ret: โโโโโโโโโโโโ (๋ฐํ๊ฐ๋ 'a)
💻 ํต์ฌ ์ฝ๋
// 1. ํจ์์ ์๋ช
์ ๋ํ
์ด์
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// 2. ๊ตฌ์กฐ์ฒด์ ์๋ช
struct Important<'a> {
part: &'a str, // ๊ตฌ์กฐ์ฒด๋ณด๋ค part๊ฐ ๋ ์ค๋ ์ด์์ผ ํจ
}
// 3. 'static: ํ๋ก๊ทธ๋จ ์ ์ฒด ๊ธฐ๊ฐ
let s: &'static str = "I live forever";
🚨 ๊ด๋ จ ์ปดํ์ผ๋ฌ ์๋ฌ
์ฐธ์กฐ๊ฐ ์๋ณธ ๊ฐ๋ณด๋ค ์ค๋ ์ด๋ ค ํ ๋ (dangling reference) ๋ฐ์.
ํจ์์ ์ ๋ ฅ/์ถ๋ ฅ ์ฐธ์กฐ ์๋ช ์ด ์ผ์นํ์ง ์์ ๋ ๋ฐ์.
🤖 AI Context Block
# Rust Concept: Lifetimes
## What They Are
Lifetimes are the compiler's way of tracking how long references are valid.
Annotations like 'a express relationships between reference lifetimes โ
they don't change how long things live.
## Rules
1. Every reference has a lifetime
2. Lifetime elision rules handle most cases automatically
3. When returning a reference, its lifetime must come from input parameters
## Code Examples
```rust
// Function lifetimes: output tied to inputs
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// Struct with reference field
struct Important<'a> {
part: &'a str,
}
impl<'a> Important<'a> {
fn announce(&self) -> &str {
self.part
}
}
// 'static: valid for entire program
let s: &'static str = "hello world";
```
## Lifetime Elision Rules (auto-inferred)
1. Each input reference gets its own lifetime
2. If exactly one input reference: output gets same lifetime
3. If &self/&mut self: output gets self's lifetime
## Compiler Errors
- E0597: value does not live long enough (dangling reference)
- E0623: lifetime mismatch between function parameters/return
## Common Mistakes
- Adding 'a everywhere when elision handles it
- Confusing lifetime annotations with runtime behavior
- Forgetting that 'a = min(all lifetimes labeled 'a)
## Related Concepts
Ownership, Borrowing, NLL, Higher-Ranked Trait Bounds (for<'a>)
โก Cheatsheet โ ๋น ๋ฅธ ์ฐธ๊ณ ์
๐ฆ ๋ฉ๋ชจ๋ฆฌ ์์น
| ์์น | ํฌ๊ธฐ | ์๋ | ์์ |
|---|---|---|---|
| Stack | ๊ณ ์ (์ปดํ์ผ ํ์) | ๋งค์ฐ ๋น ๋ฆ | i32, bool, &T |
| Heap | ๋์ (๋ฐํ์) | ์ฝ๊ฐ ๋๋ฆผ | String, Vec, Box |
| Static | ๊ณ ์ (์ ์ญ) | ์ฆ์ ์ ๊ทผ | "๋ฆฌํฐ๋ด", const |
๐ Move vs Copy vs Clone
| ๋ฐฉ์ | ๋น์ฉ | ์๋ณธ ์ ํจ | ํธ๋ฆฌ๊ฑฐ |
|---|---|---|---|
| Move | ํฌ์ธํฐ ๋ณต์ฌ | โ ๋ฌดํจ | let y = x (Heap ํ์ ) |
| Copy | ๋นํธ ๋ณต์ฌ | โ ์ ํจ | let y = x (Copy ํ์ ) |
| Clone | ์ ์ฒด ๋ณต์ | โ ์ ํจ | x.clone() ๋ช ์ |
๐ฅ ๋น๋ฆผ ๊ท์น ์์ฝ
- โ
๋ถ๋ณ ์ฐธ์กฐ(
&T) โ ์ฌ๋ฌ ๊ฐ ๋์ ๊ฐ๋ฅ - โ
๊ฐ๋ณ ์ฐธ์กฐ(
&mut T) โ ํ๋๋ง ๊ฐ๋ฅ - โ ๋ถ๋ณ + ๊ฐ๋ณ ๋์ ๋ถ๊ฐ
- ๐ก NLL: ๋ง์ง๋ง ์ฌ์ฉ ์ดํ์ ๋ค๋ฅธ ๋น๋ฆผ OK
โฐ Lifetime ๋จ์ถ์ด
| ํ๊ธฐ | ์๋ฏธ |
|---|---|
'a | ์ผ๋ฐ ์๋ช ๋งค๊ฐ๋ณ์ |
'static | ํ๋ก๊ทธ๋จ ์ ์ฒด ์๋ช |
'_ | elided lifetime (์ถ๋ก ) |
for<'a> | HRTB: ๋ชจ๋ ์๋ช |
๐ง ์ค๋งํธ ํฌ์ธํฐ ๋น๊ต
๐ ํ๋์ ๋น๊ต
| ํ์ | ์์ ์ ์ | ๊ฐ๋ณ์ฑ | ์ค๋ ๋ | ๋น์ฉ |
|---|---|---|---|---|
Box<T> | 1 | ๊ฐ๋ฅ | Send if T:Send | ๋งค์ฐ ์ ๋ ด |
Rc<T> | ๋ค์ | ๋ถ๊ฐ | โ ๋จ์ผ ์ค๋ ๋ | ์ ๋ ด (atomic ์์) |
Arc<T> | ๋ค์ | ๋ถ๊ฐ | โ ๋ฉํฐ ์ค๋ ๋ | ์ฝ๊ฐ ๋น์ (atomic) |
RefCell<T> | 1 | ๋ด๋ถ ๊ฐ๋ณ | โ ๋จ์ผ ์ค๋ ๋ | ๋ฐํ์ ๊ฒ์ฌ |
Mutex<T> | 1 | ์ ๊ธ ํ ๊ฐ๋ณ | โ ๋ฉํฐ ์ค๋ ๋ | ์ ๊ธ ๋น์ฉ |
Cow<T> | ์ฐจ์ฉ/์์ | ์ง์ฐ ๋ณ๊ฒฝ | ์ ํ์ | ๋ณ๊ฒฝ ์๋ง |
๐ณ ๊ฒฐ์ ํธ๋ฆฌ: ์ด๋ค ํฌ์ธํฐ?
Q1. ๋จ์ผ ์์ ์๋ฉด ์ถฉ๋ถํ๊ฐ?
ใโ Yes โ Box<T> (์ฌ๊ทยทtrait objectยทํฐ ๊ฐ)
Q2. ๊ณต์ ๊ฐ ํ์ํ๊ฐ? ๋ฉํฐ์ค๋ ๋์ธ๊ฐ?
ใโ ๋จ์ผ ์ค๋ ๋ โ Rc<T>
ใโ ๋ฉํฐ ์ค๋ ๋ โ Arc<T>
Q3. ๋ณ๊ฒฝ๋ ํ์ํ๊ฐ?
ใโ ๋จ์ผ ์ค๋ ๋ โ Rc<RefCell<T>>
ใโ ๋ฉํฐ ์ค๋ ๋ โ Arc<Mutex<T>>
Q4. ๊ฐ๋๋ง ์์ ๊ฐ ํ์ํ๊ฐ?
ใโ Cow<T> โ ๋ณ๊ฒฝ ์์ ์ lazy clone
๐จ ์์ฃผ ์ฐ์ด๋ ํจํด
๐๏ธ Builder Pattern
struct RequestBuilder { url: String, timeout: u32 }
impl RequestBuilder {
fn new(url: &str) -> Self { ... }
fn timeout(mut self, t: u32) -> Self {
self.timeout = t; self // Self ์์ ๊ถ ๋ฐํ
}
fn build(self) -> Request { ... }
}
// ์ฌ์ฉ: RequestBuilder::new("...").timeout(30).build();
๐ก self ์์ ๊ถ ์ด๋์ผ๋ก ๋ฉ์๋ ์ฒด์ด๋
๐ฏ Newtype Pattern
struct UserId(u64); // ํ์
์์ ์ฑ
struct OrderId(u64);
fn fetch_user(id: UserId) { ... }
// fetch_user(OrderId(5)); โ ์ปดํ์ผ ์ค๋ฅ
// fetch_user(UserId(5)); โ
๐ก ๊ฐ์ ๋ด๋ถ ํ์ ์ด๋ผ๋ ํ์ ์์คํ ์ผ๋ก ๊ตฌ๋ถ
๐ RAII (์์ ์๋ ํด์ )
struct FileGuard { f: File }
impl Drop for FileGuard {
fn drop(&mut self) {
self.f.flush().ok(); // ์ค์ฝํ ์ข
๋ฃ ์ ์๋
}
}
// ์ค์ฝํ ๋๋๋ฉด drop() ์๋ ํธ์ถ โ flush ๋ณด์ฅ
๐ก Drop trait โ Rust์ destructor
๐ Type State Pattern
struct Connection<State> { _phantom: PhantomData<State> }
struct Disconnected; struct Connected;
impl Connection<Disconnected> {
fn connect(self) -> Connection<Connected> { ... }
}
impl Connection<Connected> {
fn send(&self, msg: &str) { ... }
}
// disconnected.send() โ ์ปดํ์ผ ์ฐจ๋จ
๐ก ์ํ๋ฅผ ํ์ ์ผ๋ก โ ์๋ชป๋ ํธ์ถ์ ์ปดํ์ผ ํ์์ ์ฐจ๋จ