์ผ๋ฐ ํฌ์ธํฐ๋ ๋จ์ํ ๋ฐ์ดํฐ์ ์ฃผ์๋ฅผ ๊ฐ์ง๋ ํ์ ์ด์ง๋ง, ์ค๋งํธ ํฌ์ธํฐ๋ ๊ฐ๋ฆฌํค๋ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ๋ฉํ๋ฐ์ดํฐ๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์ค์ํฉ๋๋ค. ์ค๋งํธ ํฌ์ธํฐ๋ ํธ๋ ์ดํธ์ ์ ๋ค๋ฆญ์ ํ์ฉํด์ ๊ตฌํ๋๊ธฐ ๋๋ฌธ์ ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์ ํ์ฉํ๊ธฐ ์ํด์๋ ํธ๋ ์ดํธ์ ์ ๋ค๋ฆญ์ ์ ์ดํดํ ํ์๊ฐ ์์ต๋๋ค.
์ค๋งํธ ํฌ์ธํฐ๋ ์ฌ์ค์ ์ผ๋ฐ์ ์ธ ๊ตฌ์กฐ์ฒด์ ๋๋ค. ํ์ง๋ง ๋ค์ 2๊ฐ์ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์๋์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ํ ์ ์๊ฒ๋๋ ๊ฒ์ ๋๋ค.
- Deref ํธ๋ ์ดํธ: ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ ๋ ํผ๋ฐ์ค๋ฅผ ์ฝ์ด์ ์๋ณธ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ๊ฒ์ด ์ญ์ฐธ์กฐ(Dereference)์ ๋๋ค. ์ด๋ฐ ์ค๋งํธ ํฌ์ธํฐ๋ ์ฌ์ค์ ๊ตฌ์กฐ์ฒด๋ผ๊ณ ๋ง์๋๋ ธ์ต๋๋ค. ๊ตฌ์กฐ์ฒด๋ ํฌ์ธํฐ๊ฐ ์๋๋ ๊ตฌ์กฐ์ฒด๋ฅผ ํตํด์ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ค๋ฉด ๋ญ๊ฐ ์ถ๊ฐ์ ์ธ ๊ตฌํ์ด ํ์ํ๊ฒ ์ง์. ์ด๊ฒ ๋ฐ๋ก Deref ํธ๋ ์ดํธ์ ๋๋ค. *์ ๊ฐ์ ์ญ์ฐธ์กฐ ์ฐ์ฐ์๋ฅผ ์ค๋งํธ ํฌ์ธํฐ์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋๋ค. ์ ์ ํ์ ์ง์ ๊ตฌํํด๋ณด๋ฉด์ ๋ค์ ์ด์ผ๊ธฐํ๊ฒ ์ต๋๋ค.
- Drop ํธ๋ ์ดํธ: ์ค๋งํธ ํฌ์ธํฐ๋ ์์ ์ ์ค์ฝํ๋ฅผ ๋ฒ์ด๋๊ฒ๋๋ฉด ์๋์ผ๋ก ํด์ง๋์ด์ผํฉ๋๋ค. ๋ฌ์คํธ๋ ์ค๋งํธ ํฌ์ธํฐ๊ฐ ์ค์ฝํ๋ฅผ ๋ฒ์ด๋๋ฉด Drop ํธ๋ ์ดํธ์ drop ๋ฉ์๋๋ฅผ ํธ์ถํด์ ์ค๋งํธ ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๋ฐ์ดํฐ๋ฅผ ํด์งํฉ๋๋ค. ๊ทธ ์ธ์๋ ํ์ผ์ ๋ซ๊ฑฐ๋ํ๋ ์์ ์ ๋ฆฌ ๊ธฐ๋ฅ๋ค์ ์คํํ ์๋ ์์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ์ ์ ํ์ ์ง์ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค.
์ฐ์ ๋จผ์ ์ค๋งํธํ ๊ธฐ๋ฅ์ด ์๋ ์์ํ ํฌ์ธํฐ๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง๋ถํฐ ์์๋ณด๊ฒ ์ต๋๋ค. ๊ฑฐ์ ๋ณผ ์ผ์ ์์ง๋ง ์ด๋ฏธ ๊ตฌํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ถ์ํ๊ฑฐ๋, ์๋ฒ ๋๋ ์์คํ ๊ฐ๋ฐํ ๋์ ๊ฐ์ด ํ์ํ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
ํฌ์ธํฐ๋ ๋ค์๊ณผ ๊ฐ์ด mutable์๋๋ฉด const ์ ์ธ์ ๋ฐ๋์ ํฌํจํด์ ์ ์ธํด์ผํฉ๋๋ค.
fn main() {
let mut mutablestr = String::from("mutable");
let mutptr: *mut String = &mut mutablestr;
println!("Pointer={:?}", mutptr);
let conststr = String::from("const");
let constptr: *const String = &conststr;
println!("Pointer={:?}", constptr);
}๊ฐ๋ฆฌํค๋ ๋ฐ์ดํฐ๊ฐ mutable์ธ ํฌ์ธํฐ๋ฅผ์ ์ธํ ๋๋ ๋ฐ๋์ *mut T์ ๊ฐ์ด ํ์
์ ์ง์ ํด์ผํฉ๋๋ค.
๊ทธ๋์ mutptr์ ํ์
์ *mut String์ด ๋ฉ๋๋ค.
๋ง์ฝ ๊ฐ๋ฆฌํค๋ ๋ฐ์ดํฐ๊ฐ mutable์ด ์๋๋ผ๋ฉด mut ํค์๋๋ฅผ ์์ฐ๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํ๊ฒ ์๋๋ผ ๋ฐ๋์ const ํค์๋๋ฅผ ์จ์ฃผ์ด์ผํฉ๋๋ค.
๊ทธ ์ธ์๋ C/C++ ๊ณ์ด์์ ์ฌ์ฉํ๋ ํฌ์ธํฐ์ ๋ณ๋ก ๋ค๋ฅผ๊ฒ ์์ด๋ณด์
๋๋ค.
์์ง ์ ์๋์ง ์์ ํฌ์ธํฐ๋ฅผ ์ ์ธํ ๋๋ C/C++ ๊ณ์ด๊ณผ ๊ฐ์ด ์ ์๊ฐ 0์ผ๋ก ํฌ์ธํฐ๋ฅผ ์ด๊ธฐํํ ์๋ ์์ต๋๋ค.
let nullptr: *mut String = 0 as *mut String;๋ณดํต์ C/C++์์ ์ ์๊ฐ 0์ ์๋ฏธํ๋ NULL์ ๋ฏธ๋ฆฌ ์ ์ํด๋์ ๊ฒ์ฒ๋ผ std::ptr์๋ null()/null_mut()์ ์ ์ํด ๋์์ผ๋ ์ฌ์ฉํ๋๊ฒ ์ข์ต๋๋ค.
let const_nullptr: *const String = std::ptr::null();
let mutable_nullptr: *mut String = std::ptr::null_mut();
assert_eq!(constptr.is_null(), true);์ง๊ธ๊น์ง๋ง ๋ณด๋ฉด C/C++ ์์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ํฐ ์ฐจ์ด๊ฐ ์์ด๋ณด์ผ ์ ์์ต๋๋ค. ํ์ง๋ง ๊ฒฐ์ ์ ์ผ๋ก ํฐ ์ฐจ์ด์ ์ด ํ๋ ์๋๋ฐ ๋ฐ๋ก ํฌ์ธํฐ ์ฐ์ฐ์ ๋๋ค. ์๋์ ๊ฐ์ด ํฌ์ธํฐ ๊ฐ์ ์คํ์ ๊ฐ์ ๋ํด์ ๋ฐฐ์ด์ ์ ๊ทผํ๋ ์์ ๋ฅผ ์คํํด๋ณด๋ฉด Rust์ธ์ด๋ ํฌ์ธํฐ ๊ฐ์ ์ ์ ๊ฐ์ ๋ํ๋ ์ฐ์ฐ์ ํ์ฉํ์ง ์๋๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
fn main() {
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
for i in 0..5 {
let ptr: *const i32 = &numbers[0];
println!("Array={}", *(ptr + i));
}
}error[E0369]: cannot add `{integer}` to `*const i32`
--> src/main.rs:178:36
|
178 | println!("Array={}", *(ptr + i));
| --- ^ - {integer}
| |
| *const i32
|
help: consider using `wrapping_add` or `add` for pointer + {integer}
|
178 | println!("Array={}", *(ptr.wrapping_add(i)));
| ~~~~~~~~~~~~~~ +
๊ทธ๋ผ ์ปดํ์ผ๋ฌ๊ฐ ์๋ ค์ฃผ๋ ๋๋ก wrapping_add ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๊ด์ฐฎ์๊น์? ์๋์ ๊ฐ์ด wrapping_add ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋๋ก ๊ณ ์ณ๋ด๋ ๋ ๋ค๋ฅธ ์๋ฌ๋ฅผ ๋ง๋๊ฒ ๋ฉ๋๋ค.
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
for i in 0..5 {
let ptr: *const i32 = &numbers[0];
println!("Array={}", *ptr.wrapping_add(i));
}error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
--> src/main.rs:178:30
|
178 | println!("Array={}", *ptr.wrapping_add(i));
| ^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
|
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior ์๋ง Rust์ ๊ด์ฌ์ด ์์๋ ๋ถ๋ค์ด๋ผ๋ฉด ์ด๋ฏธ ๋ช๋ฒ์ ๋ค์ด๋ณด์ จ์ ๊ทธ ์ ๋ช ๋์ unsafe ํค์๋๋ฅผ ๋ง๋๊ฒ ๋์์ต๋๋ค. unsafe๊ฐ ๋ฌด์์ธ์ง๋ ์ด๋ฏธ ์๋ฌ ๋ฉ์ธ์ง์ ์ ๋ํ๋ ์์ต๋๋ค. ํฌ์ธํฐ๊ฐ null์ด๊ฑฐ๋ dangling(์ด๋ฏธ ํด์ง๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ)์ด๊ฑฐ๋ unaligned(๋ง์ ์๋ฒ ๋๋ ์์คํ ์์๋ ํฌ์ธํฐ ์ฃผ์๊ฐ 4๋ 8์ ๋ฐฐ์๊ฐ ๋์ด์ผ๋ง ํด๋น ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฝ์ ์ ์์ต๋๋ค)์ผ ์ ์์ผ๋, unsafe๋ผ๋ ๋ธ๋ญ์์ ๋ฉ๋ชจ๋ฆฌ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ๋ผ๋ ๊ฒ์ ๋๋ค. ๊ฒฐ๊ตญ ์ต์ข ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์คํํ ์ ์์ต๋๋ค.
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
for i in 0..5 {
let ptr: *const i32 = &numbers[0];
unsafe {
println!("Array={}", *ptr.wrapping_add(i));
}
}๊ทธ๋ฆฌ๊ณ std::ptr ๋งค๋ด์ผ์์ ์ถ์ฒํ๋ ๋๋ก ํฌ์ธํฐ๋ฅผ ์ง์ ์ฝ๋ *์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ค์๊ณผ ๊ฐ์ด read๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ฃผ๋ฉด ๊ฐ์ฅ ์์ฑ๋ ์๋ ๋ฉ๋ชจ๋ฆฌ ์ฐ์ฐ ์ฝ๋๊ฐ ๋ฉ๋๋ค.
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
for i in 0..5 {
let ptr: *const i32 = &numbers[0];
unsafe {
println!("Array={}", ptr.wrapping_add(i).read());
}
}Raw ํฌ์ธํฐ์ ๋ํ ๊ฒ์ ์ด๊ฒ ์ ๋ถ์ด๊ธด ํฉ๋๋ค๋ง ์ฌ์ค ์ค์ ํ๋ก์ ํธ์์๋ ์ด์๊ฐ์ด ์์ ํ ํฌ์ธํฐ๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ์์ต๋๋ค. ๋ค์์ ์ ๊ฐ ์์ ๋ก ๋ง๋ค์ด๋ณธ Deque ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๋ณดํต std::ptr::null() ์ ์ง์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ์๋ ์์ ์ฝ๋์ ๊ฐ์ด std::ptr::NonNull()์ ์ฌ์ฉํ๋๊ฒ ๋ ์์ ํฉ๋๋ค.
- ์ฒซ๋ฒ์งธ๋ก ์ด๊ธฐํ๋์ง ์์ ํฌ์ธํฐ๋ฅผ ์ ์ธํ ๋ NonNull::::dangling()์ผ๋ก ์ด๊ธฐํํด์, ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๊ฒ๋ ๋ฐ์ดํฐ ํ์ ์ ์ง์ ํ๊ณ align๋ ํฌ์ธํฐ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
- ํฌ์ธํฐ์ ์ ๊ทผํ ๋ as_ptr ๋ฉ์๋๋ฅผ ๊ฐ์ ๋ก ์ฌ์ฉํ๋๋กํด์ ํฌ์ธํฐ ์ ๊ทผ์ ์์ ์ฑ์ ๋์ ๋๋ค.
- offset, read, write ๋ฑ ํฌ์ธํฐ ์ ๊ทผ์ ๊ฒ์ฌํด์ฃผ๋ ๋ฉ์๋๋ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
use std::alloc;
use std::fmt;
use std::ptr::NonNull;
struct Deque {
buffer: NonNull<i32>,
capacity: isize, // buffer size
front: isize,
back: isize,
}
impl Deque {
fn new() -> Self {
Deque {
buffer: NonNull::<i32>::dangling(),
capacity: 0,
front: 0,
back: 0,
}
}
fn size(&self) -> isize {
if self.front >= self.back {
self.front - self.back
} else {
self.capacity - self.back + self.front
}
}
fn capacity(&self) -> isize {
self.capacity
}
fn empty(&self) -> bool {
self.size() == 0
}
fn full(&self) -> bool {
// -1: an entry pointed by self.back must be empty
self.size() == self.capacity() - 1
}
//
// refer: https://doc.rust-lang.org/nomicon/vec/vec-raw.html
//
fn grow(&mut self, new_cap: isize) {
// https://doc.rust-lang.org/alloc/alloc/fn.alloc.html
let new_layout = alloc::Layout::array::<i32>(new_cap as usize).unwrap();
let new_ptr = if self.capacity == 0 {
unsafe { alloc::alloc(new_layout) }
} else {
let old_layout = alloc::Layout::array::<i32>(self.capacity as usize).unwrap();
let old_ptr = self.buffer.as_ptr() as *mut u8;
unsafe { alloc::realloc(old_ptr, old_layout, new_layout.size()) }
};
self.buffer = match NonNull::new(new_ptr as *mut i32) {
Some(p) => p,
None => alloc::handle_alloc_error(new_layout),
};
self.capacity = new_cap;
}
fn front(&self) -> i32 {
if self.empty() == true {
return -1;
}
let v: i32 = unsafe { self.buffer.as_ptr().offset(self.front).read() };
v
}
fn back(&self) -> i32 {
if self.empty() == true {
return -1;
}
let v: i32 = unsafe {
self.buffer
.as_ptr()
.offset((self.back + 1) % self.capacity)
.read()
};
v
}
fn push_front(&mut self, v: i32) {
assert!(!self.full());
// move pointer and insert data
self.front = (self.front + 1) % self.capacity;
unsafe { self.buffer.as_ptr().offset(self.front).write(v) }
}
fn pop_front(&mut self) -> i32 {
if self.empty() == true {
return -1;
}
let ret = self.front();
// no need to delete data
// just move pointer backward
self.front = if self.front == 0 {
self.capacity - 1
} else {
self.front - 1
};
ret
}
fn push_back(&mut self, v: i32) {
assert!(!self.full());
// insert data and move pointer
unsafe {
self.buffer.as_ptr().offset(self.back).write(v);
}
self.back = if self.back == 0 {
self.capacity - 1
} else {
self.back - 1
};
}
fn pop_back(&mut self) -> i32 {
if self.empty() == true {
return -1;
}
let ret = self.back();
self.back = (self.back + 1) % self.capacity;
ret
}
}
impl fmt::Debug for Deque {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut v: i32;
let mut output: String = format!(
"==== Deque: capacity={} back={} front={}\n",
self.capacity, self.back, self.front
);
for i in 0..self.capacity {
v = unsafe { self.buffer.as_ptr().offset(i).read() };
if v != 0 {
output.push_str(&format!("buffer[{}]={}\n", i, v));
}
}
write!(f, "{}====", output)
}
}
impl Drop for Deque {
fn drop(&mut self) {
if self.capacity != 0 {
let layout = alloc::Layout::array::<i32>(self.capacity as usize).unwrap();
unsafe { alloc::dealloc(self.buffer.as_ptr() as *mut u8, layout) }
println!("Deque is freed");
}
}
}
fn main() {
let mut que = Deque::new();
que.grow(8);
que.push_front(1);
que.push_back(5);
println!("{:?}", que);
assert_eq!(que.front(), 1);
assert_eq!(que.back(), 5);
assert_eq!(que.pop_front(), 1);
assert_eq!(que.pop_back(), 5);
assert_eq!(que.empty(), true);
}
```bash
$ cargo run
Compiling bin-example v0.1.0 (/Users/user/study/bin-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.26s
Running `target/debug/bin-example`
==== Deque: capacity=8 back=7 front=1
buffer[0]=5
buffer[1]=1
====
Deque is freed๋์ํ๋ ์์ ๋ฅผ ๋ง๋ค๊ณ ์ถ์ด์ ์ง์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋ std::alloc๋ฅผ ์ฌ์ฉํด์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋๋ก ๋ง๋ค์ด๋ดค์ต๋๋ค๋ง ์ ๋ถ๋ฅผ ๋ค ์ดํดํ ํ์๋ ์์ต๋๋ค. ์ด๋ฐ ํํ๋ก ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด Rust ์ธ์ด์์ ์ถ์ฒํ๋ ๋ฐฉ์์ด๋ผ๋ ๊ฒ์ ์ดํดํ๋ฉด ์ถฉ๋ถํฉ๋๋ค.
์ค๋งํธ ํฌ์ธํฐ ํ์
์ด ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ต๋๋ค๋ง ๊ฐ์ฅ ํต์ฌ์ ์ธ ์ค๋งํธ ํฌ์ธํฐ๋ Box<T>ํ์
์
๋๋ค. <T>๋ผ๋ ํ์๋ ์ด ๋ฐ์ดํฐ ํ์
๋ด๋ถ์ ์ ์ฅ๋๋ ํ์
์ด ์ ๋ค๋ฆญ ํ์
์ด๋ผ๋ ๊ฒ์
๋๋ค. ์์ ์ด ์ํ๋ ์ด๋ค ๋ฐ์ดํฐ ํ์
๋ ์ ์ฅํ ์ ์๋ค๋ ์๋ฏธ์
๋๋ค.
Box<T>์ ๊ฐ์ฅ ํต์ฌ์ ์ธ ์ญํ ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ์์ญ์ ์ ์ฅํ๋ค๋ ๊ฒ์
๋๋ค. ์ฌ๊ธฐ์์ ๋ฌ์คํธ ์ธ์ด์์ ์์ฃผ ์ค์ํ ๊ฐ๋
์ด ๋์ต๋๋ค. ๋ฌ์คํธ ์ธ์ด๋ก ๊ฐ๋ฐํ๊ธฐ์ํด์๋ ๋ฐ์ดํฐ๊ฐ ํ ์์ญ์ ์ ์ฅ๋๋๋ ์คํ ์์ญ์ ์ ์ฅ๋๋๋๋ฅผ ํญ์ ์๊ฐํด์ผํฉ๋๋ค. ์คํ๊ณผ ํ ์์ญ์ ๋๊ฐ์ ๋ฉ๋ชจ๋ฆฌ์ด์ง๋ง ์์ฃผ ์ค์ํ ์ฐจ์ด์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- ์คํ ์์ญ: ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ฅผ ์ปดํ์ผ ์์ ์ ์ ์ ์์ด์ผํฉ๋๋ค. ์ปดํ์ผ๋ฌ๊ฐ ํจ์ ํธ์ถ์ ๊ดํ ์คํ ํ๋ ์์ ๋ง๋๋ ์ปดํ์ผ ์์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ๋ฅผ ๊ณ์ฐํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ ๋ณํ ์ ์์ต๋๋ค. ๋ง์ฝ ์คํ์ ์ ์ฅ๋ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ๋์ด๋๋ค๋ฉด ์คํ ํ๋ ์์ ๋ง๊ฐ์ ธ๋ฒ๋ฆด ๊ฒ์ ๋๋ค. ๋ํ์ ์ผ๋ก u32๊ฐ์ ๊ธฐ๋ณธ ํ์ ๋ค์ ํญ์ ํฌ๊ธฐ๊ฐ ๊ณ ์ ๋์ด์์ต๋๋ค. ๋ฐ๋ผ์ ๋ฐ๋ก ์คํ์ ์ ์ฅ๋ ์ ์์ต๋๋ค.
- ํ ์์ญ: ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ฅผ ์ปดํ์ผ๋ฌ๊ฐ ์ ์ ์๊ณ , ํ๋ก๊ทธ๋จ์ด ๋์ํ๋ ์ค์ ๊ฒฐ์ ๋ฉ๋๋ค. ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ๋ฐ๋ ์ ์์ต๋๋ค.
์ด์ Box<T>์ ๋์ ๋ฐฉ์์ ์ดํดํ ์ ์์ต๋๋ค.
- ์์ ๊ถ ๊ด๋ฆฌ:
Box<T>๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ์ ํ์ ์ด ๋ฌด์์ด๋ ์๊ด์์ด ๋ฐ์ดํฐ๋ฅผ ํ ์์ญ์ ์ ์ฅํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์คํ์ ์ ์ฅํฉ๋๋ค. ์์ํ๊ฒ Box๋ผ๋ ๊ตฌ์กฐ์ฒด ํ์ ์ด ์์ ๊ฒ์ ๋๋ค. ์ด Box๋ผ๋ ๊ตฌ์กฐ์ฒดํ์ ์ ๊ฐ ํ๋๋ ๊ณ ์ ๋ ํฌ๊ธฐ๋ฅผ ๊ฐ์ง๋ ํ๋๋ค์ ๋๋ค. ๋ฐ๋ผ์ Box๋ผ๋ ๊ตฌ์กฐ์ฒด์ ๊ฐ์ฒด๋ ์คํ์ ์ ์ฅ๋ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ T๋ผ๋ ๋ฐ์ดํฐ๋ ํ ์์ญ์ ์ ์ฅํฉ๋๋ค. Box๋ T์ ํฌ์ธํฐ์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ Boxํ์ ์ ๊ฐ์ฒด์ ์์ ๊ถ์ด ์ด๋ํ๊ฒ๋๊ณ , ์ต์ข ์ ์ผ๋ก Box ๊ฐ์ฒด์ ์์ ๊ถ์ด ์ฌ๋ผ์ ธ์ ํด์ง๋ ๋ Drop ํธ๋ ์ดํธ๊ฐ ์ฌ์ฉ๋์ด์ Tํ์ ์ ๊ฐ์ฒด๋ ๊ฐ์ด ํด์ง๋๋ ๊ฒ์ ๋๋ค. - ๋ฉ๋ชจ๋ฆฌ ์ญ์ฐธ์กฐ: Box ๊ฐ์ฒด ์์ ํฌ์ธํฐ๊ฐ ๋ค์ด์์ ๊ฒ์ ๋๋ค. *๋ผ๋ ์ญ์ฐธ์กฐ ์ฐ์ฐ์๋ ์ฌ์ค ํฌ์ธํฐ ํ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. Box๋ผ๋ ๊ตฌ์กฐ์ฒด์ ์ฌ์ฉํ๋ฉด ์๋ฌด๊ฒ๋ ์๋ฉ๋๋ค. ํ์ง๋ง Deref ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ธฐ ๋๋ฌธ์ ์ญ์ฐธ์กฐ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ ๋ Deref ํธ๋ ์ดํธ๋ฅผ ํตํด์ ํ ์์ญ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ๊ฒ์ ๋๋ค.
์ฌ์ฉ๋ฒ์ ๊ฐ๋จํฉ๋๋ค. Box๋ผ๋ ๊ตฌ์กฐ์ฒด์ new ๋ฉ์๋์ ์์ ์ด ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋๊ฒ ๋ฟ์ ๋๋ค.
fn main() {
let my_data = Box::new(10);
println!("What is in the heap?: {}", my_data);
}$ cargo run
Compiling pyalgo v0.1.0 (/Users/user/study/pyalgo)
Finished dev [unoptimized + debuginfo] target(s) in 0.88s
Running `target/debug/pyalgo`
What is in the heap?: 10๊ทธ๋ผ my_data๋ผ๋ ์ค๋งํธ ํฌ์ธํฐ๊ฐ ๋ง๋ค์ด์ก์ต๋๋ค. my_data๋ผ๋ Box<i32>ํ์
๊ตฌ์กฐ์ฒด๋ ์คํ์ ์์ฑ๋์๊ณ , 10์ด ์ ์ฅ๋ i32ํ์
๋ฐ์ดํฐ๋ ํ์ ์ ์ฅ๋์์ต๋๋ค. ํฌ๊ฒ ์ค์ํ๊ฑด ์๋์ง๋ง ํ๊ฐ์ง ๋ ์คํ์ ํด๋ณด๊ฒ ์ต๋๋ค. my_data๊ฐ ์คํ์ ์ ์ฅ๋์ด์๊ณ , i32ํ์
๋ฐ์ดํฐ๊ฐ ํ์ ์ ์ฅ๋์ด์๋ ๊ฒ์ ์ฆ๋ช
ํด๋ณด๊ฒ ์ต๋๋ค. ๋ค์ ์์ ๋ฅผ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
fn main() {
let my_data = Box::new(10);
println!("What is in the heap?: {}", my_data);
println!("At stack: {:p}", &my_data);
println!("At heap: {:p}", my_data.as_ref());
}$ cargo run
Compiling pyalgo v0.1.0 (/Users/user/study/pyalgo)
Finished dev [unoptimized + debuginfo] target(s) in 0.88s
Running `target/debug/pyalgo`
What is in the heap?: 10
At stack: 0x7ffef0c2e9b8
At heap: 0x5d21262e2b80๊ฒฐ๊ณผ๊ฐ์ ๋ณด๋ฉด my_data๋ผ๋ ๋ณ์๊ฐ ์์นํ ๊ณณ์ ์ฃผ์๊ฐ์ด 0x7ffef0c2e9b8์ด๊ณ Box์ as_ref๋ฉ์๋๊ฐ ๋ฐํํ ๊ฐ์ด 0x5d21262e2b80์
๋๋ค. as_ref๋ ๋ฉ๋ด์ผ์ ์ฐพ์๋ณด๋ฉด Box<T>์์ &T๋ฅผ ๋ฐํํ๋ค๊ณ ์จ์์ต๋๋ค. ํ์ ์ ์ฅ๋ ๋ฐ์ดํฐ์ ํฌ์ธํฐ๋ฅผ ๋ฐํํ๋ ๊ฒ์
๋๋ค. ๋ฆฌ๋
์ค์์๋ ์ด ๋ฉ๋ชจ๋ฆฌ ๊ฐ์ผ๋ก ํ์ธ์ง ์คํ์ธ์ง ํ์ธํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ์๋์๊ฐ์ด ์ดํ๋ฆฌ์ผ์ด์
์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ์ถ๋ ฅํด๋ณผ ์ ์์ต๋๋ค.
$ cat /proc/$$/maps
563bb63d6000-563bb6404000 r--p 00000000 fc:02 16909610 /usr/bin/bash
563bb6404000-563bb64df000 r-xp 0002e000 fc:02 16909610 /usr/bin/bash
563bb64df000-563bb6518000 r--p 00109000 fc:02 16909610 /usr/bin/bash
563bb6518000-563bb651c000 r--p 00141000 fc:02 16909610 /usr/bin/bash
563bb651c000-563bb6525000 rw-p 00145000 fc:02 16909610 /usr/bin/bash
563bb6525000-563bb6530000 rw-p 00000000 00:00 0
563bb7090000-563bb71d1000 rw-p 00000000 00:00 0 [heap]
...์๋ต
7fffdb5c4000-7fffdb5e5000 rw-p 00000000 00:00 0 [stack]
7fffdb5f2000-7fffdb5f6000 r--p 00000000 00:00 0 [vvar]
7fffdb5f6000-7fffdb5f8000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]์ดํ๋ฆฌ์ผ์ด์ ๋ง๋ค ์ธ๋ถ ๊ฐ๋ค์ ๋ค๋ฅด์ง๋ง ์ ๊ฐ ์คํํ ์์ ์คํ ์์ญ์ ์ฃผ์๊ฐ์ 7fffdb5c4000-7fffdb5e5000์ด๊ณ , ํ ์์ญ์ ์ฃผ์๊ฐ์ 55fb3f245000-55fb3f4a9000์ธ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ๋ฌผ๋ก ์์ ์ ๋ฉ๋ชจ๋ฆฌ ์์ญ๊ณผ ์ ํํ ๊ฐ์ ๋ค๋ฅด๊ฒ ์ง๋ง, ๋ชจ๋ ์ดํ๋ฆฌ์ผ์ด์ ์ ์คํ ์์ญ์ ์ฃผ์๊ฐ์ด 0x7fff๋ก ์์ํ๊ณ ํ ์์ญ์ ์ฃผ์๊ฐ์ด 0x55fb๋ก ์์ํ๋ ๊ฒ์ ๋ค๋ฅด์ง ์์ ๊ฒ์ ๋๋ค. ์๋ํ๋ฉด ๋ฆฌ๋ ์ค ์ปค๋์ด ํ๋ก๊ทธ๋จ์ ์คํํ ๋ ๊ทธ๋ ๊ฒ ์ง์ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด์จ๋ ๊ฒฐ๋ก ์ ์ผ๋ก ์์ ๋ฅผ ์คํํด๋ณด๋ฉด Box๋ผ๋ ๋ฐ์ดํฐ ํ์ ์ ์คํ ์์ญ์ ์กด์ฌํ๊ณ , ํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๋ฐ์ดํฐ๋ ํ ์์ญ์ ์กด์ฌํ๊ณ ์์์ ํ์ธํ ์ ์์ต๋๋ค.
Box<T>๋ฅผ ์ ์ดํดํ๊ธฐ ์ํด์ ์์ฃผ ๋จ์ํ ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์ง์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค. Box<T>๋ ๋ค์ํ ๋ฉ์๋๋ค์ด ์์ง๋ง, ์ฐ๋ฆฌ๋ ์ค๋งํธ ํฌ์ธํฐ์ ๊ฐ์ฅ ํต์ฌ ๊ธฐ๋ฅ์ธ ์ญ์ฐธ์กฐ์ ์๋ ๋ฉ๋ชจ๋ฆฌ ํด์ง๋ง์ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค.
// src/smart_pointer_basic/main.rs
use std::ops::{Deref, DerefMut};
struct MySmartPointer<T>(T);
impl<T> MySmartPointer<T> {
fn new(x: T) -> MySmartPointer<T> {
MySmartPointer(x)
}
}
impl<T> Deref for MySmartPointer<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for MySmartPointer<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T> Drop for MySmartPointer<T> {
fn drop(&mut self) {
println!("Dropping MySmartPointer");
}
}
fn main() {
let my_pointer = MySmartPointer::new(5);
println!("Value: {}", *my_pointer);
let mut mut_pointer = MySmartPointer::new(1);
*mut_pointer = 2;
println!("Value: {}", *mut_pointer);
}$ cargo run --bin smart_pointer_basic
Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.15s
Running `target/debug/smart_pointer_basic`
Value: 5
Value: 2
Dropping MySmartPointer
Dropping MySmartPointer๊ฐ์ฅ ๋จผ์ Deref, DerefMut ๋๊ฐ์ง ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋๋ก ์ ์ธํฉ๋๋ค.
use std::ops::{Deref, DerefMut};๊ทธ๋ฆฌ๊ณ MySmartPointer๋ผ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค. ์ ๋ค๋ฆญ์ ์ฌ์ฉํด์ ์ ๋ค๋ฆญ ํ์ ์ T์ ๋๋ค. ๊ตฌ์กฐ์ฒด ์์ฒด๋ ๊ฐ์ฅ ๋จ์ํ๊ฒ ๋ฐ์ดํฐ๋ง ํฌํจํ๋๋ก ๋ง๋ญ๋๋ค.
struct MySmartPointer<T>(T);์ฌ์ค์ ์ด ๊ตฌ์กฐ์ฒด๋ ์ค๋งํธํฌ์ธํฐ๊ฐ ์๋๋๋ค. ๋ฐ์ดํฐ๋ฅผ ํ์ ์ ์ฅํ๋๊ฒ ์๋๋ผ ์คํ์ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ํ์ง๋ง ํ์ ๋ฉ๋ชจ๋ฆฌ ํ ๋นํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์๊ฐํ์ง์์์ผ๋ ํ๋ด๋ง ๋ด๊ธฐ ์ํด์ ์คํ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค.
MySmartPointer๋ฅผ ์์ฑํ๋ new ๋ฉ์๋๋ฅผ ๊ตฌํํฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋ฐ์ดํฐ x๋ฅผ ๋ฐ์์ ๊ทธ๋๋ก ์ ์ฅํ ๋ฟ์ ๋๋ค.
impl<T> MySmartPointer<T> {
fn new(x: T) -> MySmartPointer<T> {
MySmartPointer(x)
}
}์ด์ Deref ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํฉ๋๋ค.
impl<T> Deref for MySmartPointer<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}deref๋ผ๋ ๋ฉ์๋๊ฐ ์๋๋ฐ ์ค๋งํธํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๋ฐ์ดํฐ์ ๋ ํผ๋ฐ์ค๋ฅผ ๋ฐํํ๋๋ก ๊ตฌํํ๋ฉด ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ฉด *์ฐ์ฐ์์ ๊ฒฐํจํด์ *&T๊ฐ ๋๋ฏ๋ก ๊ฒฐ๊ตญ ํ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ๋๋ ๊ฒ์ ๋๋ค.
๋ค์์ DerefMut ํธ๋ ์ดํธ์ ๋๋ค. mut์ด๋ผ๋ ์ด๋ฆ์ด ๋ถ์ ๊ฒ์์ ์ ์ ์๋ฏ์ด ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ฟ ์ ์๋ mutable ๋ ํผ๋ฐ์ค &mut T๋ฅผ ๋ฐํํด์ค๋๋ค.
impl<T> DerefMut for MySmartPointer<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}DerefMutํธ๋ ์ดํธ์ ์ฌ์ฉ๋ฒ์ mainํจ์์์ ๋ณผ ์ ์์ต๋๋ค.
๋ค์์ Drop ํธ๋ ์ดํธ์ ๊ตฌํ์ ๋๋ค.
impl<T> Drop for MySmartPointer<T> {
fn drop(&mut self) {
println!("Dropping MySmartPointer");
}
}์ฌ์ค ์ฐ๋ฆฌ ๋ฐ์ดํฐ๋ ์คํ์ ์ ์ฅ๋๋ฏ๋ก ์ค์ ๋ก ํ๋ ์ผ์ ์์ต๋๋ค. ๋ง์ฝ ๋ฉ๋ชจ๋ฆฌ ํ ๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ํ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ์ผ๋ฉด, drop ๋ฉ์๋์์ ๋ฉ๋ชจ๋ฆฌ ํด์ง๋ฅผ ํ๋ฉด ๋ฉ๋๋ค.
๋ค์์ mainํจ์๋ฅผ ๋ณด๊ฒ ์ต๋๋ค. ๋จผ์ Derefํธ๋ ์ดํธ๋ฅผ ์ด์ฉํด์ ์ค๋งํธํฌ์ธํฐ๊ฐ ๊ฐ๋ฆฌํค๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ๋ง ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
fn main() {
let my_pointer = MySmartPointer::new(5);
println!("Value: {}", *my_pointer);my_pointer๋ ํฌ์ธํฐ์ ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก *์ฐ์ฐ์๋ฅผ ๋ถ์ด๋ฉด ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ์ ์์ต๋๋ค. ๋ง์ฝ Derefํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ์ง์์์ผ๋ฉด ๊ทธ๋ฅ ์ผ๋ฐ ๊ตฌ์กฐ์ฒด ์ด๋ฆ์ *๋ฅผ ๋ถ์ธ ๊ฒ์ด๋ฏ๋ก ์๋ฌด ๋์๋ ํ์ง ์์ ๊ฒ์ ๋๋ค.
๊ทธ ๋ค์์๋ DerefMut ํธ๋ ์ดํธ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
let mut mut_pointer = MySmartPointer::new(1);
*mut_pointer = 2;
println!("Value: {}", *mut_pointer);
}mut_pointer๋ผ๋ ๋ณ์๋ ๋ฐ์ดํฐ๊ฐ ๋ฐ๋ ๊ฒ์ด๋ฏ๋ก ๋ฐ๋์ mut ์ ์ธ์ด ์์ด์ผํฉ๋๋ค. ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊พธ๋ ๋ฐฉ๋ฒ์ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋์ผํฉ๋๋ค. "*ํฌ์ธํฐ์ด๋ฆ" ํํ๋ก ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง์ผ๋ก mainํจ์์ ์ค์ฝํ๊ฐ ๋๋๋ฉด ๋๊ฐ์ ์ค๋งํธํฌ์ธํธ๊ฐ ๋ชจ๋ ์ฌ๋ผ์ง๊ฒ ๋ฉ๋๋ค. ์ด๋ Drop ํธ๋ ์ดํธ์ drop ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค.
์ค๋งํธ ํฌ์ธํฐ๋ ๋ฐ์ดํฐ๋ฅผ ํ ์์ญ์ ์ ์ฅํ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค. ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ํฌ๊ฑฐ๋ ๋์ ์ผ๋ก ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ๋ณํ๋ค๋ฉด ์ค๋งํธ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ ์๋ฐ์ ์์ต๋๋ค. ๋ํ์ ์ผ๋ก ๋คํธ์ํฌ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ๋ฐ์ดํฐ์ ํฌ๊ธฐ๋ ํด ๊ฒ์ด๊ณ , ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ์ผ๋ง๋๋ ์ง๋ ์ปดํ์ผ ์์ ์๋ ์ ๋ ์ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ ์ธ์ Box<T>๋ผ๋ ํ์
์ ๋ฐ๋์ ์ฌ์ฉํด์ผํ๋ ๊ฒฝ์ฐ๊ฐ ํ๋ ๋ ์์ต๋๋ค. ์ด์ ์ ํธ๋ ์ดํธ๋ฅผ ์ค๋ช
ํ ๋ ํธ๋ ์ดํธ ๊ฐ์ฒด์ ๋ํด์ ์ด์ผ๊ธฐํ์์ต๋๋ค. ๋ค์ ํ๋ฒ ์ด์ผ๊ธฐํ๋ฉด ์ด๋ค ํจ์๊ฐ ํน์ ํ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ํ์
๋ง์ ์ ๋ฌ๋ฐ์ ์ ์๋๋ก ๋ง๋๋ ๋ฐฉ๋ฒ์
๋๋ค. ์ฌ๋ฌ๊ฐ์ ๊ตฌ์กฐ์ฒด๊ฐ ์๋๋ฐ ๋ชจ๋ A๋ผ๋ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ์ต๋๋ค. ๊ทธ๋ผ ์ด ๊ตฌ์กฐ์ฒด๋ค์ ๋ฒกํฐ๋ ๋ฐฐ์ด์ ๋ชจ์๋๊ณ ์ถ์ ๋๊ฐ ์์ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด์ GenSerialData๋ผ๋ ํน์ ํ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ํ์
๋ค์ ํ๋์ ๋ฒกํฐ์ ๋ชจ์์ ํ๊บผ๋ฒ์ ์ฒ๋ฆฌ๋๋๋ก ๋ง๋ค๊ณ ์ถ์ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ค ์ ์์ต๋๋ค.
use std::io::{stdin, stdout, Write};
fn get_user_input() -> String {
let mut s = String::new();
let _ = stdout().flush();
stdin()
.read_line(&mut s)
.expect("Did not enter a correct string");
if let Some('\n') = s.chars().next_back() {
s.pop();
}
if let Some('\r') = s.chars().next_back() {
s.pop();
}
s
}
trait GenSerialData {
fn get_input(&mut self);
fn generate(&self) -> Option<&str>;
}
struct UserID {
digit: u32,
id: Option<String>,
}
impl GenSerialData for UserID {
fn get_input(&mut self) {
println!("Please input {}-digits User ID: ", self.digit);
self.id = Some(get_user_input());
}
fn generate(&self) -> Option<&str> {
self.id.as_ref().map(|x| x.as_str())
}
}
struct ProductID {
digit: u32,
id: Option<String>,
}
impl GenSerialData for ProductID {
fn get_input(&mut self) {
println!("Please input {}-digits Product ID: ", self.digit);
self.id = Some(get_user_input());
}
fn generate(&self) -> Option<&str> {
self.id.as_ref().map(|x| x.as_str())
}
}
fn collect_data(items: &mut [&dyn GenSerialData]) {
for item in items.iter_mut() {
item.get_input();
}
}
fn generate_serial(items: &[&dyn GenSerialData]) -> String {
let mut data = String::new();
for item in items.iter() {
data.push_str(item.generate().unwrap());
}
data
}
fn main() {
let userid = UserID { digit: 4, id: None };
let product = ProductID { digit: 8, id: None };
let mut items = [&userid, &product];
collect_data(&mut items);
let serial = generate_serial(&items);
println!("Serial generated: {}", serial);
}$ cargo run --bin smart_pointer_application
Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
error[E0308]: mismatched types
--> src/smart_pointer_application/main.rs:73:31
|
73 | let mut items = [&userid, &product];
| ^^^^^^^^ expected `&UserID`, found `&ProductID`
|
= note: expected reference `&UserID`
found reference `&ProductID`
error[E0596]: cannot borrow `**item` as mutable, as it is behind a `&` reference
--> src/smart_pointer_application/main.rs:57:9
|
57 | item.get_input();
| ^^^^ cannot borrow as mutable
Some errors have detailed explanations: E0308, E0596.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `my-rust-book` (bin "smart_pointer_application") due to 2 previous errors์ด ์์ ๋ ์ฌ์ฉ์ ID๊ณผ ์ ํ ID๋ฅผ ์กฐํฉํด์ ์ ํ์ ์๋ฆฌ์ผ๋ฒํธ๋ฅผ ๋ง๋๋ ์์ ์ ๋๋ค. UserID๋ผ๋ ๊ตฌ์กฐ์ฒด์ ProductID๋ผ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค์์ต๋๋ค. ์ด ๋๊ฐ์ง ๊ตฌ์กฐ์ฒด๋ ๋๊ฐ์ ์ธํฐํ์ด์ค๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํ๋ก๊ทธ๋จ์ ์คํํ๋ ์ฌ์ฉ์๋ก๋ถํฐ (์๋ง๋ ์ ํ์ ๊ด๋ฆฌํ๋ ์์ ๋ถ์์ ์ง์๋ ๊ฒ ๊ฐ๋ค์) ์ ๋ ฅ์ ๋ฐ์์ ๋ฌธ์์ด๋ก ์ ์ฅํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์๋ฆฌ์ผ ๋ฒํธ๋ฅผ ๋ง๋ค ๋ ์์ ์ ๊ฐ์ ๋ฐํํด์ฃผ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก GenSerialData๋ผ๋ ํธ๋ ์ดํธ๋ฅผ UserID์ ProductID๊ฐ ๊ตฌํํ ์ ์์ต๋๋ค. ๋์ค์ ์ฌ์ฉ์ID์ ์ ํID์ธ์๋ ์ ์ํํ์ ์ฌ์ฉ ๋ง๊ธฐ ๋ ์ง๋ ํ๋งค ๋ ์ง ๋ฑ ๋ค์ํ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ์๋ฆฌ์ผ ๋ฒํธ์ ๋ฃ์ ์ ์๋๋ก ํ์ฅ์ด ๊ฐ๋ฅํฉ๋๋ค. ์๋ก์ด ๋ฐ์ดํฐ์ ํ์ ์ ๋ง๋ค๊ณ GenSerialData๋ผ๋ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ธฐ๋ง ํ๋ฉด ๋๋๊น์.
ํต์ฌ์ ์ธ ์ญํ ์ ํ๋ ํจ์๊ฐ ๋ฐ๋ก collect_data์ generate_serial ํจ์์ ๋๋ค.
fn collect_data(items: &mut [&dyn GenSerialData]) {
for item in items.iter_mut() {
item.get_input();
}
}
fn generate_serial(items: &[&dyn GenSerialData]) -> String {
let mut data = String::new();
for item in items.iter() {
data.push_str(item.generate().unwrap());
}
data
}ํธ๋ ์ดํธ ๊ฐ์ฒด์ ๋ฐฐ์ด์ ์ ๋ฌ๋ฐ์์ ๋ชจ๋ ํธ๋ ์ดํธ ๊ฐ์ฒด์ ๊ณตํต ๋ฉ์๋ get_input๊ณผ generate๋ฅผ ํธ์ถํ๋ ํจ์์ ๋๋ค. ์๋ฆฌ์ผ ๋ฒํธ์ ๋ค์ด๊ฐ์ผ๋๋ ๋ชจ๋ ๋ฐ์ดํฐ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ํ๊บผ์ ์ ์ ๋ ฅํ๊ณ ์ถ๋ ฅํ๋ ๋ฃจํ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ ๊ฐ์ค๋ฝ๊ฒ๋ ์ด ์์ ์ฝ๋๋ ๋น๋๋์ง ์์ต๋๋ค. userid์ productid์ ๋ ํผ๋ฐ์ค๋ฅผ ์ ์ฅํ๋ items์์ ๋น๋ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ฐฐ์ด์ด๋ ๋ฒกํฐ๋ ๋์ผํ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๋๋ค. ํ์ง๋ง ์ด ์์ ์์๋ ๋์ผํ ํ์ ์ ์ ์ฅํ๋๊ฒ ์๋๋ค. &userid๋ UserID ๊ตฌ์กฐ์ฒด ํ์ ์ ๋ ํผ๋ฐ์ค์ด๊ณ , &productid๋ ProductID์ ๋ ํผ๋ฐ์ค์ด๊ธฐ ๋๋ฌธ์ ์๋ก ๋ค๋ฅธ ํ์ ์ ๋๋ค. ํ๋์ ๋ฐฐ์ด์ ์ ์ฅ๋ ์ ์์ต๋๋ค. ๋น๋ก ๋ ๋ ํผ๋ฐ์ค๊ฐ ๋ชจ๋ ๊ฐ์ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ํ์ ์ ๋ ํผ๋ฐ์ค์ด์ง๋ง, ๋์ผํ ํ์ ์ ์๋๋๋ค. ๊ฐ์ ๋ฐ๋ก ํธ๋ ์ดํธ ๊ฐ์ฒด๋ก ์ฌ์ฉ๋ ์๋ ์์ง๋ง, ํ๋์ ๋ฐฐ์ด์ ์ ์ฅ๋ ์ ์์ต๋๋ค.
ํ์ง๋ง ์ด ๋ ๊ฐ์ฒด๋ฅผ Box<T>์ ๋ด๋๋ค๋ฉด ์ด์ผ๊ธฐ๋ ๋ฌ๋ผ์ง๋๋ค. ๋ฐฐ์ด์ ์ ์ฅ๋๋ ๊ฒ์ Boxํ์
์
๋๋ค. ๊ทธ๋ผ Box๋ฅผ ์ฌ์ฉํ๋๋ก ๋ฐ๊ฟ๋ณด๊ฒ ์ต๋๋ค.
// src/smart_pointer_application/main.rs
use std::io::{stdin, stdout, Write};
fn get_user_input() -> String {
let mut s = String::new();
let _ = stdout().flush();
stdin()
.read_line(&mut s)
.expect("Did not enter a correct string");
if let Some('\n') = s.chars().next_back() {
s.pop();
}
if let Some('\r') = s.chars().next_back() {
s.pop();
}
s
}
trait GenSerialData {
fn get_input(&mut self);
fn generate(&self) -> Option<&str>;
}
struct UserID {
digit: u32,
id: Option<String>,
}
impl GenSerialData for UserID {
fn get_input(&mut self) {
println!("Please input {}-digits User ID: ", self.digit);
self.id = Some(get_user_input());
}
fn generate(&self) -> Option<&str> {
self.id.as_ref().map(|x| x.as_str())
}
}
struct ProductID {
digit: u32,
id: Option<String>,
}
impl GenSerialData for ProductID {
fn get_input(&mut self) {
println!("Please input {}-digits Product ID: ", self.digit);
self.id = Some(get_user_input());
}
fn generate(&self) -> Option<&str> {
self.id.as_ref().map(|x| x.as_str())
}
}
//fn collect_data(items: &mut Vec<Box<dyn GenSerialData>>) { // If you want to use Vec<Box<dyn GenSerialData>> in main function
fn collect_data(items: &mut [Box<dyn GenSerialData>]) {
for item in items.iter_mut() {
item.get_input();
}
}
// &[&dyn GenSerialData] is wrong!
//fn generate_serial(items: &Vec<Box<dyn GenSerialData>>) -> String { // If you want to use Vec<Box<dyn GenSerialData>> in main function
fn generate_serial(items: &[Box<dyn GenSerialData>]) -> String {
let mut data = String::new();
for item in items.iter() {
data.push_str(item.generate().unwrap());
}
data
}
fn main() {
println!("hello");
let userid = UserID { digit: 4, id: None };
let productid = ProductID { digit: 8, id: None };
// Vec<&dyn GenSerialData> is wrong!
//let mut items: Vec<Box<dyn GenSerialData>> = vec![Box::new(userid), Box::new(productid)];
let mut items: [Box<dyn GenSerialData>; 2] = [Box::new(userid), Box::new(productid)];
collect_data(&mut items);
let serial = generate_serial(&items);
println!("Serial generated: {}", serial);
}$ cargo run --bin smart_pointer_application
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/smart_pointer_application`
hello
Please input 4-digits User ID:
1234
Please input 8-digits Product ID:
qwerasdf
Serial generated: 1234qwerasdf์ด์ ์์ ์์๋ ์๋์ ๊ฐ์ด ๋ฐฐ์ด์ ์ฌ์ฉํ์ต๋๋ค.
fn collect_data(items: &mut [&dyn GenSerialData]) {
...
fn generate_serial(items: &[&dyn GenSerialData]) -> String {
...
let mut items = [&userid, &product];๋ฐฐ์ด์ ์ฌ์ฉํ๋ ๋ชจ๋ ํจ์ ์ธ์์ items ๋ณ์ ์ ์ธ ๋ถ๋ถ์ Box๋ก ๋ฐ๊ฟจ์ต๋๋ค.
fn collect_data(items: &mut [Box<dyn GenSerialData>]) {
...
fn generate_serial(items: &[Box<dyn GenSerialData>]) -> String {
...
let mut items: [Box<dyn GenSerialData>; 2] = [Box::new(userid), Box::new(productid)];๊ทธ๋ฆฌ๊ณ items์ ๋ฐฐ์ด์ด ์๋๋ผ ๋ฒกํฐ๋ก ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ์๋์ ๊ฐ์ด ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
fn collect_data(items: &mut Vec<Box<dyn GenSerialData>>) { // If you want to use Vec<Box<dyn GenSerialData>> in main function
...
fn generate_serial(items: &Vec<Box<dyn GenSerialData>>) -> String { // If you want to use Vec<Box<dyn GenSerialData>> in main function
...
let mut items: Vec<Box<dyn GenSerialData>> = vec![Box::new(userid), Box::new(productid)];ํ๊ฐ์ง ์ฃผ์ํด์ผํ ๊ฒ์ด ํ์ ์ง์ ์ ๋ฐ๋์ ํด์ผํ๋ค๋ ๊ฒ์ ๋๋ค.
let mut items = vec![Box::new(userid), Box::new(productid)];
let mut items = [Box::new(userid), Box::new(productid)];๋ง์ฝ ์์ ๊ฐ์ด ํ์ ์ง์ ์ ์ง์ด๋ค๋ฉด ์ปดํ์ผ๋ฌ๋ ๋ฐฐ์ด์ UserID ํ์ ์ ํฌ์ธํฐ๊ฐ ์ ์ฅ๋๋ ๊ฒ์ธ์ง, ProductID ํ์ ์ ํฌ์ธํฐ๊ฐ ์ ์ฅ๋์ด์ผํ๋ ๊ฒ์ธ์ง๋ฅผ ํ๋จํ ์ ์์ต๋๋ค. ๋ฐ๋์ ํธ๋ ์ดํธ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ค๊ณ ํ์ ์ ์จ์ฃผ์ด์ผํฉ๋๋ค.
๊ทธ ์ธ์๋ ๋ช๊ฐ์ง ์ค๋งํธ ํฌ์ธํฐ๊ฐ ๋ ์์ต๋๋ค. ๊ฐ๊ธฐ ๋ค๋ฅธ ์ฉ๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํ์ง๋ง ๋ค๋ฅธ ์ค๋งํธ ํฌ์ธํฐ๋ค์ ๋ณดํต ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ด๋ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์์ ์ฌ์ฉ๋๋ ๊ฒ๋ค์ด๋ผ์ ์ด ์ฑ ์์๋ ์์ธํ ์๊ฐํ์ง ์๊ฒ ์ต๋๋ค. ๊ฐ๋จํ ์ด๋ฆ๊ณผ ์ฉ๋๋ง ์๊ฐํ๊ฒ ์ต๋๋ค.
Rc<T>,Arc<T>: ์์ ๊ถ์ ์ฌ๋ฌ๊ฐ ๋ง๋ค์ด์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์์ต๋๋ค.Rc<T>๋ ์ฑ๊ธ์ฐ๋ ๋์์ ํธ๋ฆฌ๋ ๊ทธ๋ํ์ ๊ฐ์ด ์๋ก๊ฐ ์๋ก๋ฅผ ์ฐธ์กฐํ๋ ํํ์ ์ฌ์ฉํฉ๋๋ค.Arc<T>๋ ๋ฉํฐ์ฐ๋ ๋์์ ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ๊ณต์ ํ๋ ๋ฐ์ดํฐ์ ์ฌ์ฉํฉ๋๋ค.RefCell<T>: ์ด๋ค ๋ฐ์ดํฐ์ ๋ถ๋ณํ(Immutable) ๋ ํผ๋ฐ์ค๋ฅผ ๊ฐ์ง๊ณ ์๋ ์ํฉ์์๋, ๋ฐ์ดํฐ๋ฅผ ์์ ๊ฐ๋ฅํ๋๋ก ๋ง๋ค์ด์ค๋๋ค. ๋ณดํต์ ์์ ํ์ง ์์ง๋ง, ์ ๋ง ์์ธ์ ์ธ ๊ฒฝ์ฐ์ ์์ ๊ฐ๋ฅํ๋๋ก ๋ง๋ค์ด์ผ๋ ๋ ์ฌ์ฉํฉ๋๋ค.Cell<T>: ๊ฑฐ์ ์ฌ์ฉ๋ ์ผ์ด ์์ง๋ง, ํน์ ๊ฐ์ฒด์ ๋ํด ์์ ํ ์์ ๊ฐ๋ฅํ๋ฉด์ ๋์์ ๊ณต์ ๊ฐ๋ฅํ ํฌ์ธํฐ๋ฅผ ๋ง๋ญ๋๋ค. ๋ณดํต C/C++ ์ธ์ด์ ๋ฌ์คํธ ์ธ์ด๋ฅผ ๊ฐ์ด ์ฌ์ฉํ ๋ C/C++์ ํฌ์ธํฐ ๋ณ์์ ์ ๊ทผํ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค.Mutex<T>,RwLock<T>: ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด ๋ฝ์ ๊ตฌํํ ํ์ ๋ค์ ๋๋ค.