์ ๋ค๋ฆญ ํ๋ก๊ทธ๋๋ฐ์ ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ฐ์ ์ฝ๋๋ฅผ ๋ค๋ฅธ ํ์ ์ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ์ ๋๋ค. ์ ๋ค๋ฆญ์ ์ด์ฉํ ํ์ (๊ตฌ์กฐ์ฒด์ ์ด๊ฑฐํ)๊ณผ ์ ๋ค๋ฆญ์ ์ด์ฉํ ํจ์(์ผ๋ฐ ํจ์, ๋ฉ์๋, ํธ๋ ์ดํธ ๋ฑ)์ ๋ง๋ค ์ ์๋๋ฐ ์๋๋ฐ ๋ค์ ์์ ๋ก ์ ๋ค๋ฆญ ํ์ , ํจ์, ํธ๋ ์ดํธ์ ๋ํด์ ์์๋ณด๊ฒ ์ต๋๋ค.
// src/generic_struct/main.rs
#[derive(Debug)]
struct Pair<T> {
first: T,
second: T,
}
fn add<T>(a: T, b: T) -> T
where
T: std::ops::Add<Output = T>,
{
a + b
}
impl<T> std::ops::Add for Pair<T>
where
T: std::ops::Add<Output = T> + Copy,
{
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self {
first: self.first + rhs.first,
second: self.first + rhs.second,
}
}
}
fn main() {
let left_pair: Pair<i32> = Pair {
first: 5,
second: 10,
};
let right_pair: Pair<i32> = Pair {
first: 10,
second: 5,
};
let result = add(left_pair, right_pair);
println!("Sum: {:?}", result);
let left_pair_u32: Pair<u32> = Pair {
first: 5,
second: 10,
};
let right_pair_u32: Pair<u32> = Pair {
first: 10,
second: 5,
};
let result = add(left_pair_u32, right_pair_u32);
println!("Sum: {:?}", result);
}
$ cargo run --bin generic_struct
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
Running `target/debug/generic_struct`
Sum: Pair { first: 15, second: 10 }
Sum: Pair { first: 15, second: 10 }
์ฝ๋๋ฅผ ํ๋์ฉ ๋ฏ์ด๋ณด๊ฒ ์ต๋๋ค. ๊ฐ์ฅ ๋จผ์ Pair๋ผ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค์์ต๋๋ค.
#[derive(Debug)]
struct Pair<T> {
first: T,
second: T,
}
ํ์ ํ๋ผ๋ฏธํฐ๋ T์ ๋๋ค. T์๋ ๋ค์ํ ํ์ ๋ค์ด ์ฌ ์ ์์ต๋๋ค. u32๊ฐ์ ๊ธฐ๋ณธ ํ์ ๋ ์ฌ์ฉ๋ ์ ์๊ณ , ๋ค๋ฅธ ๊ตฌ์กฐ์ฒด ํ์ ๋ ์ฌ ์ ์์ต๋๋ค.
C++ ์ธ์ด์ ์ ๋ค๋ฆญ๊ณผ ์์ ํ ๋์ผํ ๋ฌธ๋ฒ์ ๊ฐ์ง๊ณ ์๊ณ , ํ์ด์ ๋ฑ์ ๋ค๋ฅธ ์ธ์ด๋ค์์ ์ ๋ค๋ฆญ์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ๋ ๊ฑฐ์ ๋์ผํ๋ฏ๋ก, ๋ค๋ฅธ ์ธ์ด์์ ์ ๋ค๋ฆญ์ ์ ํด๋ณด์ ๋ถ๋ค์ ์ฝ๊ฒ ์ฌ์ฉํ์ค ์ ์์ต๋๋ค.
๊ทธ ๋ค์์ ์ผ๋ฐ ํจ์ add์ ๋๋ค.
fn add<T>(a: T, b: T) -> T
where
T: std::ops::Add<Output = T>,
{
a + b
}
ํ์ ํ๋ผ๋ฏธํฐ๋ T์ ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก T์๋ ๋ค์ํ ํ์ ๋ค์ด ์ฌ ์ ์์ต๋๋ค. ์ธ์๊ฐ ๋๊ฐ ์๋๋ฐ ๋ ์ธ์๊ฐ ๋ฐ๋์ ๊ฐ์ ํ์ ์ด์ด์ผ๋ง ํฉ๋๋ค. ๊ฐ์ ํ์ ์ ์ธ์๋ฅผ ๋๊ฐ ๋ฐ์์ ๋ ์ธ์๋ฅผ ํฉํ ๊ฐ์ ๋ฐํํฉ๋๋ค. ๋ฌ์คํธ์์ ์ ๊ณตํ๋ ์ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ด ์๋๋ฐ, ๋ฌ์คํธ์ ์ ๋ค๋ฆญ ํจ์์๋ ํ์ ํ๋ผ๋ฏธํฐ๊ฐ ์ด๋ค ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด์ผํ๋์ง๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค.
where
T: std::ops::Add<Output = T>,
์ด๋ ๊ฒ where์ ์ ์ถ๊ฐํ๋ฉด Tํ์ ์ std::ops::Addํธ๋ ์ดํธ๋ฅผ ๋ฐ๋์ ๊ตฌํํ๊ณ ์์ด์ผํ๋ฉฐ Add ํธ๋ ์ดํธ์์ ์ฌ์ฉํ๋ Outputํ์ ์ T๊ฐ ๋์ด์ผํ๋ค๋ ์ ์ฝ์กฐ๊ฑด์ ๊ฑธ๊ฒ๋ฉ๋๋ค. where๋ฅผ ์์ฐ๊ณ ์๋์๊ฐ์ด ํ์ค์ ํ์ ์ ๋ค ์จ์ค๋ ๋ฉ๋๋ค. ์ ๋ ์ ๋ค๋ฆญ ํ์ ์ ๋ํด์ ๊ฐ์กฐ๋ฅผ ํ๊ธฐ ์ํด์ where๋ฅผ ์จ์ ๋ถ๋ฆฌํด์ ํ๊ธฐ๋ฅผ ํ์ต๋๋ค.
fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
a + b
}
์๋์๊ฐ์ด ์ ์๋ ์ค์๋ฅผ addํจ์์ ์ ๋ฌํ ์ ์๋ค๋ ๊ฒ์ ์ ์๋ ์ค์ ํ์ ์ด ๋ด๋ถ์ ์ผ๋ก ์ด๋ฏธ std::ops::Add ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
let result = add(3.14, 1.618);
println!("Sum: {}", result); // Prints "Sum: 4.758"
์ ์๋ ์ค์๊ฐ std::ops::Add ํธ๋ ์ดํธ๋ฅผ ์ด๋ฏธ ๊ตฌํํ๊ณ ์๊ธฐ ๋๋ฌธ์ add ํจ์์ ์ฌ์ฉ๋ ์ ์๋ค๋ฉด, ๊ทธ๋ผ ์ฐ๋ฆฌ๊ฐ ๋ง๋ Pair๋ผ๋ ํ์ ๋ ๋ง์ฐฌ๊ฐ์ง๋ก std::ops::Add ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ค๋ฉด addํจ์๋ฅผ ์ด์ฉํ ์ ์๋ค๋ ์๋ฏธ๊ฐ ๋ฉ๋๋ค. Pairํ์ ์ ์ํ std::ops::Add ํธ๋ ์ดํธ ๊ตฌํ์ ํด๋ณผ๊น์.
impl<T> std::ops::Add for Pair<T>
where
T: std::ops::Add<Output = T> + Copy,
{
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self {
first: self.first + rhs.first,
second: self.first + rhs.second,
}
}
}
์ด์ ์ ํธ๋ ์ดํธ๋ฅผ ์๊ฐํ ๋ ๊ตฌํํด๋ณธ ๊ฒ๊ณผ ์กฐ๊ธ ๋ ๋ณต์กํด์ก์ต๋๋ค. ๊ฐ ์ฐจ์ด์ ๋ค์ ํ๋์ฉ ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
๊ฐ์ฅ ๋จผ์ Pair ํ์ ์ด ์ ๋ค๋ฆญ ํ์ ์ด๊ธฐ ๋๋ฌธ์ Pairํ์ ์ ์ฌ์ฉํ๊ธฐ ์ํด์ ํธ๋ ์ดํธ ๊ตฌํ์๋ ๋๊ฐ์ด <T>๋ผ๋ ํ์ ์ง์ ์ด ์ถ๊ฐ(์ด๋ ๊ฒ ์ ๋ค๋ฆญ์์ ํ์ ์ด ์ง์ ๋๋ ๊ฒ์ ๋ฐ์ธ๋ฉ์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค)๋์์ต๋๋ค. impl<T>์ Pair<T> ์ด๋ ๊ฒ 2๊ตฐ๋ฐ์ ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
impl<T> std::ops::Add for Pair<T>
addํจ์์์ Tํ์ ์ด std::ops::Add ํธ๋ ์ดํธ ๊ตฌํ์ด ๋์ด์์ด์ผํ๋ค๋ ์ ํ์ ํ์ต๋๋ค. ๊ทธ๋์ Pair๋ฅผ ์ํ ํธ๋ ์ดํธ ๊ตฌํ์์๋ ์๋์๊ฐ์ด Tํ์ ์ด std::ops::Add ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด์ผํ๋ค๋ ์ ์ฝ์ ์ถ๊ฐํฉ๋๋ค.
where
T: std::ops::Add<Output = T> + Copy,
์ฌ๊ธฐ์ Copyํธ๋ ์ดํธ๊ฐ ์ถ๊ฐ๋์๋๋ฐ์ addํจ์์์ self์ธ์๊ฐ ์ฐธ์กฐ๊ฐ ์๋๋ผ ๊ฐ์ด ๋์ด๊ฐ๋ ๊ฒ์ด๊ธฐ๋๋ฌธ์ ์์ ๊ถ์ ์ด๋์ด ์ผ์ด๋๊ธฐ ๋๋ฌธ์ ๋๋ค. addํจ์์ self์ธ์๊ฐ &self์๊ฐ์ ์ฐธ์กฐ๊ฐ ์๋์ ์ ๋ด์ฃผ์ธ์. Copy ํธ๋ ์ดํธ๋ฅผ ์ถ๊ฐํ์ง์๊ณ ๋น๋ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
error[E0382]: use of moved value: `self.first`
--> src/main.rs:15:21
|
14 | first: self.first + rhs.first,
| ---------------------- `self.first` moved due to usage in operator
15 | second: self.first + rhs.second,
| ^^^^^^^^^^ value used here after move
|
note: calling this operator moves the left-hand side
--> /Users/user/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/arith.rs:92:12
|
92 | fn add(self, rhs: Rhs) -> Self::Output;
| ^^^^
= note: move occurs because `self.first` has type `T`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0382`.
๊ณ ๋ง๊ฒ๋ Copy ํธ๋ ์ดํธ๋ฅผ ์ถ๊ฐํ๋ผ๊ณ ์๋ ค์ฃผ๊ณ ์์ต๋๋ค. ์ง๊ธ ๋จ๊ณ์์ ์ ์ดํด๊ฐ ์๋๋ค๊ณ ํด๋ ์ปดํ์ผ๋ฌ๊ฐ ์๋ ค์ฃผ๋๋๋ก Copy๋ฅผ ์ถ๊ฐํด์ ์ผ๋จ ๋น๋๊ฐ๋๋๋ก ๋ง๋ค๊ณ ์ฒ์ฒํ ์ดํดํด๋ ์ข์ต๋๋ค.
Copy ํธ๋ ์ดํธ๋ Marker ํธ๋ ์ดํธ๋ก ์์ ๊ถ์ด ์ด๋ํ ๋ ์ด ํ์ ์ด ๋นํธ๋จ์๋ก ๋ณต์ฌํ๋ฉด ๊ฐ์ด ์ด๋๋ ์ ์๋ค๋ ํ์๋ฅผ ํ ๊ฒ์ ๋๋ค. ์ค์ ๋ก ๊ตฌํํด์ผํ๋ ํจ์๊ฐ ์๋ ๊ฒ์ ์๋๋๋ค. ๋ณดํต Clone ํธ๋ ์ดํธ๋ ๊ฐ์ฒด๋ ๊ฐ์ด ๋ณต์ฌํ๋ Deep copy๋ฅผ ์ํํ๋๋ฐ Copy๋ ๋นํธ๋จ์ ๋ณต์ฌ๋ง ์คํํฉ๋๋ค. ์ฆ ํฌ์ธํฐ ๊ฐ๋ง ๋ณต์ฌ๋๊ณ ๊ฐ์ฒด๋ ๋ณต์ฌ๋์ง ์์ต๋๋ค. ํฌ์ธํฐ์ธ์๋ i32๊ฐ์ ๊ธฐ๋ณธ ํ์ ์๋ Copy ํธ๋ ์ดํธ๊ฐ ๊ตฌํ๋์ด์์ต๋๋ค. ์ฐ๋ฆฌ ์ฝ๋์์ self๊ฐ ์ธ์๋ก ๋์ด๊ฐ ๋ ๋นํธ๋จ์๋ก ๋ณต์ฌ๋์ด์ ์ ๋ฌ๋ฉ๋๋ค.
std::ops::Add ํธ๋ ์ดํธ์ ๊ตฌํ์ ๋ณด๊ฒ ์ต๋๋ค.
{
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self {
first: self.first + rhs.first,
second: self.first + rhs.second,
}
}
}
๋ ํ์ ์ ๋ํ ๊ฒฐ๊ณผ๋ฌผ์ ๊ฐ์ ํ์ ์ด ๋๋๊ฒ ๋ณดํต์ด๊ฒ ์ง์. ๊ทธ๋์ Output์ Self ํ์ ์ผ๋ก ์ง์ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ add๋ฉ์๋๋ฅผ ๊ตฌํํฉ๋๋ค. add ๋ฉ์๋์ ๋ฐํ๊ฐ์ ํจ์ ๋ด๋ถ์์ ์๋กญ๊ฒ ๋ง๋ค์ด์ง Selfํ์ ์ ๊ฐ์ฒด์ ๋๋ค. first์ second ํ๋๋ฅผ ๊ฐ๊ฐ ๊ณ์ฐํด์ ์๋ก์ด Self ํ์ ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋ฐํํฉ๋๋ค.
๊ทธ๋์ ์ต์ข ์ ์ผ๋ก mainํจ์์์ Pairํ์ ์ ๋ ๋ณ์, left_pair์ right_pair๋ฅผ addํจ์์ ์ ๋ฌํ ์ ์๊ฒ๋ฉ๋๋ค.
fn main() {
let left_pair: Pair<i32> = Pair {
first: 5,
second: 10,
};
let right_pair: Pair<i32> = Pair {
first: 10,
second: 5,
};
let result = add(left_pair, right_pair);
println!("Sum: {:?}", result);
...
์ฌ๊ธฐ์์ result์ ํ์ ์ด ์๋ต๋์์ง๋ง Pair<i32>ํ์ ์ด๋ผ๋ ๊ฒ์ ์์๋ผ ์ ์์ด์ผํฉ๋๋ค.
์ด์๊ฐ์ด ๋ฌ์คํธ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ธฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฑ์ ์๋ ํจ์๋ ํธ๋ ์ดํธ๋ฑ์ ๋๋ถ๋ถ ์ ๋ค๋ฆญ์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ์ด๊ฒ๋ค์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋จผ์ ํด๋น ์ ๋ค๋ฆญ ํ์ ํ๋ผ๋ฏธํฐ๊ฐ ์ด๋ค ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด์ผํ๋์ง๋ฅผ ํ์ธํด์, ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ณ ๊ทธ ๋ค์ ์ ๋ค๋ฆญ ํจ์๋ ํธ๋ ์ดํธ๋ฅผ ์ด์ฉํ๋ฉด ๋ฉ๋๋ค. ์ด๋ ๊ฒ ์ ๋ค๋ฆญ๊ณผ ํธ๋ ์ดํธ๋ฅผ ๊ฐ์ด ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ๊ฐ ๊ฑฐ์ ๋๋ถ๋ถ์ ๋๋ค. ์ฒ์์๋ ๋ง์ด ๋ฏ์ค๊ณ ์ดํดํ๊ธฐ ์ฝ์ง ์์ง๋ง, ๋ช๋ฒ ๋ง๋ค๋ค๋ณด๋ฉด ์ต์ํด์ง๋๋ค.
๊ตฌ์กฐ์ฒด ํ์ ์ ์ ์ฉ๋ ์ ๋ค๋ฆญ์ ์ฌ์ฉํด๋ดค์ผ๋๊น ์ด๋ฒ์๋ ํธ๋ ์ดํธ์ ์ ์ฉ๋ ์ ๋ค๋ฆญ์ ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค. ์๋ ์์ ๋ ์ด์ ์ ํธ๋ ์ดํธ๋ฅผ ์ค๋ช ํ๋ฉด์ ์ฌ์ฉํ๋ Printable ํธ๋ ์ดํธ ๊ตฌํ ์์ ๋ฅผ ์ ๋ค๋ฆญ์ ์ฌ์ฉํ๋๋ก ๋ฐ๊พผ ์์ ์ ๋๋ค.
// src/generic_trait/main.rs
trait Printable<AGE> {
fn print(&self);
fn get_age(&self) -> AGE;
}
struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: &str, age: u32) -> Self {
Person {
name: name.to_string(),
age: age,
}
}
}
impl Printable<u32> for Person {
fn print(&self) {
println!("Name: {}, {} years old", self.name, self.age);
}
fn get_age(&self) -> u32 {
self.age
}
}
fn print_info(item: &dyn Printable<u32>) {
item.print();
}
fn main() {
let person: Person = Person::new("Alice", 22);
print_info(&person);
}
$ cargo run --bin generic_trait
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/generic_trait`
Name: Alice, 22 years old
ํธ๋ ์ดํธ๋ฅผ ์ค๋ช ํ๋ฉด์ Printable ํธ๋ ์ดํธ์ ์๋์ ๊ฐ์ด ์ฐ๊ด ํ์ ์ ์ฌ์ฉํ ์ ์๋ค๊ณ ์ค๋ช ํ์์ต๋๋ค.
trait Printable {
type Age;
fn print(&self);
fn get_age(&self) -> Self::Age;
}
์ ๋ค๋ฆญ์ ์๋ค๋ฉด ์ด๊ฒ์ ์๋์๊ฐ์ด ์ ๋ค๋ฆญ์ผ๋ก ๋ฐ๊ฟ ์ ์์ต๋๋ค.
trait Printable<AGE> {
fn print(&self);
fn get_age(&self) -> AGE;
}
๊ทธ๋ฆฌ๊ณ Printable์ ๊ตฌํํ๊ฑฐ๋ ์ฌ์ฉํ ๋๋ โAge=u32โ๋ผ๋ ์ฐ๊ด ํ์ ์ง์ ์ ์ธํ์์์ด ์ ๋ค๋ฆญ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์์ต๋๋ค.
impl Printable<u32> for Person {
fn print(&self) {
println!("Name: {}, {} years old", self.name, self.age);
}
fn get_age(&self) -> u32 {
self.age
}
}
fn print_info(item: &dyn Printable<u32>) {
item.print();
}
print_info์ ์ ๋ฌํ ํธ๋ ์ดํธ ๊ฐ์ฒด๋ <u32>์ด๋ผ๋ ํ์ ๋ฐ์ธ๋ฉ์ ๊ฐ์ง๊ณ ์์ด์ผํฉ๋๋ค. ํธ๋ ์ดํธ ๊ฐ์ฒด์ ์ ๋ค๋ฆญ์ด ๊ฒฐํฉ๋๊ฒ ํ๋ฒ์ ๋์ ๋ค์ด์ค์ง ์์ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ 3๋จ๊ณ๋ก ์๊ฐํ๋ฉด ์ข์ต๋๋ค.
- print_info์ ์ ๋ฌ๋๋ ์ธ์๋ ํ๋์ ํ์ ์ด ์๋๋ผ, ๋ค์ํ ํ์ ์ ๋ ํผ๋ฐ์ค๋ฅผ ๋ฐ์ ์ ์๋ค.
- print_info์ ์ ๋ฌ๋๋ ํ์ ์ Printable์ด๋ผ๋ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ํ์ ์ ๋ ํผ๋ฐ์ค์ด๋ค.
- Printable์ด๋ผ๋ ํธ๋ ์ดํธ๊ฐ ๋ฐ๋์ u32 ํ์ ์ ์ํด ๊ตฌํ๋์ด์ผํ๋ค.
์ ๋๋ฆญ๊ณผ ์ฐ๊ด ํ์ ์ค์์ ์ด๋๊ฒ ๋ ๊ฐ๋จํ๋ค๊ณ ๋จ์ ํ ์๋ ์์ต๋๋ค๋ง, ์ ๋ค๋ฆญ์ผ๋ก ์ง์ ํ๋ ํ์ ์ด u32, i8๊ฐ์ ๊ธฐ๋ณธ ํ์ ์ด ์๋๋ผ ๋๋ค๋ฅธ ๊ตฌ์กฐ์ฒด ํ์ ์ด๋ผ๋ฉด ์ ๋ค๋ฆญ์ ์ฌ์ฉํ๋๊ฒ ๋ ๊ฐ๋จํ ๋๊ฐ ๋ง์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ํธ๋ ์ดํธ์๋ ์ ๋ค๋ฆญ์ด ์ฌ์ฉ๋๊ณ , ๊ตฌ์กฐ์ฒด์๋ ์ ๋ค๋ฆญ์ด ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ๊ฐ ์ค๋ฌด์์ ๋ ์ผ๋ฐ์ ์ผ ๊ฒ์ ๋๋ค.
// src/generic_trait_struct/main.rs
trait Printable<AGE> {
fn print(&self);
fn get_age(&self) -> AGE;
}
#[derive(Debug)]
struct Address {
post: u32,
city: String,
}
impl Default for Address {
fn default() -> Self {
Address {
post: 0,
city: "Unknown".to_string(),
}
}
}
struct Person<ADDR> {
name: String,
age: u32,
location: ADDR,
}
impl<ADDR> Person<ADDR> {
fn new(name: &str, age: u32, addr: ADDR) -> Self {
Person {
name: name.to_string(),
age: age,
location: addr,
}
}
}
impl<ADDR> Printable<u32> for Person<ADDR> {
fn print(&self) {
println!("Name: {}, {} years old", self.name, self.age);
}
fn get_age(&self) -> u32 {
self.age
}
}
fn print_info(item: &dyn Printable<u32>) {
item.print();
}
fn main() {
let alice: Person<Address> = Person::new("Alice", 22, Address::default());
print_info(&alice);
println!("Alice is at : {:?}", alice.location);
let bruce: Person<String> = Person::new("Bruce", 33, "NewYork".to_string());
println!("Bruce is at : {:?}", bruce.location);
}
$ cargo run --bin generic_trait_struct
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s
Running `target/debug/generic_trait_struct`
Name: Alice, 22 years old
Alice is at : Address { post: 0, city: "Unknown" }
Bruce is at : "NewYork"
์์ ๊ฐ ๋ณต์กํด๋ณด์ด์ง๋ง ์ด 2๊ฐ์ง์ ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ฐ๊ณ ์๊ณ , ๊ฐ๊ฐ์ด ๋ฌด์์ ์ํ ํ์ ์ธ์ง๋ฅผ ๊ธฐ์ตํ๋ฉด์ ์์ํด๋ณด๊ฒ ์ต๋๋ค.
- ํธ๋ ์ดํธ Printable์ AGE ํ์ ํ๋ผ์ดํฐ: ๋์ด๋ฅผ ํํํ๋ ํ์ ์ ๋๋ค.
- ๊ตฌ์กฐ์ฒด Person์ ADDR ํ์ ํ๋ผ๋ฏธํฐ: ์ฃผ์๋ฅผ ํํํ๋ ํ์ ์ ๋๋ค.
์ฝ๊ฐ์ ์๋ น์ด ์๋๋ฐ Person ๊ตฌ์กฐ์ฒด์ ํ์ ์ ๊ตฌํํ ๋๋ ํญ์ Person<ADDR>๋ก ์ฌ์ฉํ๋ค๊ณ ๊ธฐ์ตํ๋ฉด ํธํฉ๋๋ค. Printable ํธ๋ ์ดํธ์ ๊ตฌํ ์ฝ๋์์๋ Person<ADDR>๊ณผ ๊ฐ์ด ์ ๋ค๋ฆญ ํ์ ์ ํญ์ ์จ์ค์ผํ๋ค๋๊ฑธ ์ฃผ์ํด์ผํฉ๋๋ค.
impl<ADDR> Person<ADDR> {
...
impl<ADDR> Printable<u32> for Person<ADDR> {
...
๊ทธ๋ผ ์์ ์ฝ๋๋ฅผ ์ชผ๊ฐ์ ํ๋์ฉ ์ฝ์ด๋ณด๊ฒ ์ต๋๋ค. ๊ฐ์ฅ ๋จผ์ ๋ Printable์ด๋ผ๋ ํธ๋ ์ดํธ๋ฅผ ์ ์ธํฉ๋๋ค.
trait Printable<AGE> {
fn print(&self);
fn get_age(&self) -> AGE;
}
Printable์ด๋ผ๋ ํธ๋ ์ดํธ๊ฐ ์๋๋ฐ ์์ง ๊ตฌํ์ ์๋์ด์์ต๋๋ค. ๋จ์ง ๊ทธ๋ฐ ํธ๋ ์ดํธ๊ฐ ์๊ณ , print์ get_age๋ผ๋ ๋ฉ์๋๋ค์ด ์๋ค๋ ๊ฒ์ ์ ์ธํ ๊ฒ์ ๋๋ค. get_age๋ AGE๋ผ๋ ์ ๋ค๋ฆญ ํ์ ์ ๋ฐํํ๊ฒ๋ฉ๋๋ค. ๋์ด๋ ๋ณดํต ์ ์๊ฐ์ด ๋๊ฒ ์ง๋ง, ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ๋ ์๋๋ด ๋๋ค. ์ด์จ๋ ์ ๋ค๋ฆญ ํ์ ์ด๋ ๋์ค์ Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ์ฝ๋์์ AGE ํ์ ์ ๋ฌด์์ผ๋กํ ์ง ์ ํ๊ฒ๋ ๊ฑฐ๋ผ๋ ์์์ ํ ์ ์์ต๋๋ค.
๊ทธ ๋ค์์ Address๋ผ๋ ๊ตฌ์กฐ์ฒด ํ์ ์ ๋ง๋ค๊ณ ์์ต๋๋ค.
#[derive(Debug)]
struct Address {
post: u32,
city: String,
}
impl Default for Address {
fn default() -> Self {
Address {
post: 0,
city: "Unknown".to_string(),
}
}
}
๋ณ๋ค๋ฅผ๊ฒ ์๋ ๊ตฌ์กฐ์ฒดํ์ ์ ๋๋ค. Default ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด์คฌ์ต๋๋ค. city๋ผ๋ ํ๋๊ฐ ๋ํดํธ๊ฐ์ด๋ผ๋ฉด ๋ณดํต ๋น ๋ฌธ์์ด์ด ๋๊ฒ ์ง๋ง, ๊ตณ์ด "Unknown"์ผ๋ก ์ด๊ธฐํ๋ ์ ์๋๋ก, Default ํธ๋ ์ดํธ๋ฅผ ์ง์ ๊ตฌํํ ๊ฒ์ ๋๋ค.
๊ทธ ๋ค์์ Person์ด๋ผ๋ ๊ตฌ์กฐ์ฒด ํ์ ์ ๋๋ค.
struct Person<ADDR> {
name: String,
age: u32,
location: ADDR,
}
impl<ADDR> Person<ADDR> {
fn new(name: &str, age: u32, addr: ADDR) -> Self {
Person {
name: name.to_string(),
age: age,
location: addr,
}
}
}
์ฌ๋์ ์ด๋ฆ, ๋์ด, ์์น๋ฅผ ์ ์ฅํ๋ ๊ตฌ์กฐ์ฒด์ ๋๋ค. ์์น๊ฐ ๊ผญ ์ง ์ฃผ์๊ฐ์ ๋ฌธ์์ด์ด ๋ ํ์๋ ์์ผ๋ฏ๋ก ADDR์ด๋ผ๋ ์ ๋ค๋ฆญ ํ์ ์ ์ฌ์ฉํด์คฌ์ต๋๋ค. ์ฐํธ๋ฒํธ๋ ๋ ์ ์๊ณ , ์ขํ๋ ๋ ์ ์์ผ๋ Post๋ Coordinates๊ฐ์ด ์๋ก์ด ํ์ ์ ์ฌ์ฉํ ์๋ ์๊ฒ ๋ค์. ๊ทธ๋์ ์ ๋ค๋ฆญ ํ์ ์ผ๋ก ๋ง๋ค์๋๋ด ๋๋ค. impl<ADDR> Person<ADDR>๊ณผ ๊ฐ์ด ADDR์ด๋ผ๋ ์ ๋ค๋ฆญ ํ์ ์ ์ด๋์ ์จ์ค์ผ๋๋์ง๋ฅผ ์ ๋ด์ฃผ์ธ์.
์ด์ ์ฐ๋ฆฌ๊ฐ ๋ณด๊ณ ์ํ๋ ์ฝ๋๊ฐ ๋์ต๋๋ค. ์ ๋ค๋ฆญ ํ์ ์ ์ฌ์ฉํ ๊ตฌ์กฐ์ฒด์ ์ ๋ค๋ฆญ ํ์ ์ ์ฌ์ฉํ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ์ฝ๋์ ๋๋ค.
impl<ADDR> Printable<u32> for Person<ADDR> {
fn print(&self) {
println!("Name: {}, {} years old", self.name, self.age);
}
fn get_age(&self) -> u32 {
self.age
}
}
์ฒซ์ค์ ํธ๋ ์ดํธ ๊ตฌํ์ ์ ์ธํ๋ ์ฝ๋์ธ๋ฐ 2๊ฐ์ ์ ๋ค๋ฆญ ํ์ ์ด ๋์์ ๋์ค๋ฏ๋ก ๋์ ์ ์๋ค์ด์ต๋๋ค. ํ๊ธ๋ก ๋ค์ ์จ๋ณด๊ฒ ์ต๋๋ค.
impl<๊ตฌ์กฐ์ฒด์ ์ ๋ค๋ฆญ ํ์
> ํธ๋ ์ดํธ<ํธ๋ ์ดํธ์ ์ ๋ค๋ฆญ ํ์
> for ๊ตฌ์กฐ์ฒด์ด๋ฆ<๊ตฌ์กฐ์ฒด์ ์ ๋ค๋ฆญ ํ์
> {
Printable ํธ๋ ์ดํธ๊ฐ u32ํ์ ์ผ๋ก ๊ตฌํ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ ๋ค๋ฆญ ํ์ ์ ์ฌ์ฉํ๋ get_age๋ผ๋ ํจ์๊ฐ u32 ํ์ ์ ๋ฐํํ๊ฒ๋ฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก print_info์ ์ ๋ฌ๋๋ ํธ๋ ์ดํธ ๊ฐ์ฒด๊ฐ Printable<u32> ํ์ ์ด ๋ฉ๋๋ค.
fn print_info(item: &dyn Printable<u32>) {
Printable<i32>๋ Printable<String>๋ฑ๋ฑ ์ ๋ค๋ฆญ ํ์ ์ด ๋ค๋ฅธ Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ํ์ ๋ค์ print_info์ ์ ๋ฌ ๋ ์ ์์ต๋๋ค. ์ค์ง Printable<u32>๋ง์ด ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
ํธ๋ ์ดํธ์ ๊ตฌ์กฐ์ฒด, ์ด๊ฑฐํ์ ๋ชจ๋ ์ ๋ค๋ฆญ ํ์ ์ด ์ฌ์ฉ๋๋ฉด ์ฌ๋ฌ๊ฐ์ ์ ๋ค๋ฆญ ํ์ ์ด ์ฌ์ฉ๋๊ณ , ์ด๋๊ฒ ์ด๋์ ๋ฐ์ธ๋ฉ๋ ํ์ ์ธ์ง ํท๊ฐ๋ฆด ์ ์์ต๋๋ค. ์กฐ๊ธ ์๊ฐ์ด ํ์ํ ๋ถ๋ถ์ด๋ฏ๋ก ์กฐ๊ธํ๊ฒ ์๊ฐํ์ง๋ง๊ณ ์ฒ์ฒํ ์ ์ํด๋๊ฐ๋๋ก ํฉ์๋ค. ์กฐ๊ธ์ฉ ์ฝ๊ณ ์ฐ๋ค๋ณด๋ฉด ๊ทธ ํธ๋ฆฌํจ๊ณผ ์ ์ฐํจ์ ์ฆ๊ธธ ์ ์๋ ์๊ฐ์ด ์ฌ ๊ฒ์ ๋๋ค.
๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ๊ณผ ์ ๋ค๋ฆญ ํ๋ก๊ทธ๋๋ฐ ๋ฑ์ ์ง์ ์ ์ฉํด์ ์ํํธ์จ์ด๋ฅผ ์ค๊ณํ๊ณ ๊ตฌํํด๋ณด๋ ๊ฒฝํ์ ํด๋ณด๊ธฐ๋ ์ฝ์ง ์์ต๋๋ค. ๋ณดํต์ ์ด๋ฏธ ๊ฐ์ฒด์งํฅ์ด๋ ์ ๋ค๋ฆญ ํ๋ก๊ทธ๋๋ฐ์ ๊ณ ๋ คํด์ ์ค๊ณ๋ ์ํํธ์จ์ด๋ฅผ ์์ ํ๊ฑฐ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ์ ๋ฌด๋ฅผ ํ๊ฒ๋ฉ๋๋ค. ๋ฐ๋ผ์ ๋ฌ์คํธ๋ฅผ ์ฒ์ ์ ํ๋ ๋จ๊ณ์์ ํธ๋ ์ดํธ๋ ์ ๋ค๋ฆญ์ ๋ํด์ ์ดํด๊ฐ ์๋๊ฑฐ๋, ๊ฐ๋ ์ ์ดํด๊ฐ ๋๋๋ผ๋ ๋ง์ ์ ์ฉ์ ์ด๋ป๊ฒ ํด์ผํ ์ง ๋๊ฐํ๊ฒ ๋๊ปด์ง๋๊ฒ ๋น์ฐํ ์ผ์ผ ๊ฒ์ ๋๋ค. ์ ๋ ์ฒ์์๋ ํธ๋ ์ดํธ์ ์ ๋ค๋ฆญ์ ๋ํด์ ์์ํ๊ธฐ ์ฝ์ง ์์์ง๋ง ๋ช๊ฐ์ง ํ๋ก์ ํธ์ ์ฐธ์ฌํ๋ฉด์ ์กฐ๊ธ์ฉ ์ต์ํด์ง ์ ์์์ต๋๋ค. ์ฐธ๊ณ ๊ฐ ๋์ค์ง๋ ๋ชจ๋ฅด๋ ์ ๊ฐ ์๋ํด๋ณธ ๋ฐฉ๋ฒ๋ค์ ๋ง์๋๋ฆฌ๊ฒ ์ต๋๋ค.
- ์ผ๋จ์ ํธ๋ ์ดํธ์ ์ ๋ค๋ฆญ์ ์๊ฐํ์ง์๊ณ ๋น์ฅ ๋์ํ๋๋ก ๊ตฌํํฉ๋๋ค. ์์ง ์ต์ํ์ง์์ ๊ฐ๋ ์ ๊ฐ๋ฐ ์ด๊ธฐ ๊ฐ๋ฐ๋จ๊ณ์์ ์ ์ฉํ๋ ๊ฒ์ ๋ฌด๋ฆฌ์ ๋๋ค. ์ผ๋จ์ ๋์์๋ง ์ง์คํด์ ๊ตฌํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ์ค ํ๋กํ ํ์ ์ ๋ง๋๋ ๋จ๊ณ์์ ์์ฃผ ํต์ฌ ๊ธฐ๋ฅ๋ง์ ๊ตฌํํ๋๋ฐ ํธ๋ ์ดํธ์ ์ ๋ค๋ฆญ์ ์ฌ์ฉํ ํ์๋ ์์ ์ ์์ต๋๋ค. ์ต์ํ์ ํ์ ๊ธฐ๋ฅ๋ง์ ์ ๋์ํ๋๋ก ๋ง๋๋๋ฐ ์ง์คํฉ๋๋ค.
- ํ์ ๊ธฐ๋ฅ์ด๋ ์ํํธ์จ์ด์ ๋ผ๋๊ฐ ๋๋ ๋ชจ๋๋ค๋ง ๊ตฌํํ ํ์๋ ์ ์ฐจ ์ํํธ์จ์ด์ ๊ท๋ชจ๋ฅผ ๋๋ ค๋๊ฐ ๊ฒ์ ๋๋ค. ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ณ , ์ข๋ ๊ฐ ๋ชจ๋์ ์ ์ฐํ๊ฒ ๋ง๋ค๊ณ , ์ ์ ๋ฆฌ๋ ์ธํฐํ์ด์ค๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ฒ ๋ค๋ฌ์ด๋๊ฐ ๊ฒ์ ๋๋ค. ์ด์ ๋ ๋จ๊ณ๊ฐ๋๋ฉด ์กฐ๊ธ์ฉ ๋ฐ๋ณต๋๋ ํจํด๋ค์ด ์๊ฒจ๋๊ฒ๋๊ณ ํธ๋ ์ดํธ๋ ์ ๋ค๋ฆญ์ผ๋ก ํด๊ฒฐํ ์ ์๊ฒ๋ฉ๋๋ค.
- ๊ฐ์ฒด๋ค๊ฐ์ ๋ฐ๋ณต๋๋ ํน์ฑ์ด ์๊ฑฐ๋ ๊ณตํต์ ์ธ ๋์์ ํธ๋ ์ดํธ๋ก ์ ๋ฆฌํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํธ๋ ์ดํธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ํจ์๋ฅผ ๋ง๋ค์ด์ ํ์คํ๋ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ญ๋๋ค. ์ค์ง ํด๋น ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ๊ฐ์ฒด๋ค๋ง ์ฌ์ฉํ ์ ์๋ ์ธํฐํ์ด์ค๊ฐ ์๊ธด๋ค๋ฉด, ์ถํ์ ๋ณธ์ธ์ด ์๋ ๋๊ฐ ๊ฐ๋ฐ์ ์ฐธ์ฌํ๋ค๊ณ ํด๋ ์์ฐ์ค๋ฝ๊ฒ ํ์ค ์ธํฐํ์ด์ค๋ง์ ์ฌ์ฉํ ์๋ฐ์ ์์ต๋๋ค.
- ๊ตฌ์กฐ์ฒด๋ ์ด๊ฑฐํ ํ์ ์ ์ ๋ค๋ฆญ์ ์ฌ์ฉํ ๋๋ ํธ๋ ์ดํธ ๊ตฌํ์ ํญ์ ๊ฐ์ด ์๊ฐํด์ผํฉ๋๋ค. ๊ตฌ์กฐ์ฒด์ ์ ๋ค๋ฆญ ํ์ ์ ์ถ๊ฐํ์ ๋ ์ด ์ ๋ค๋ฆญ ํ์ ์ด u32, char๊ฐ์ ์ผ๋ฐ ํ์ ์ด ์๋๋ผ ๋ ๋ค๋ฅธ ๊ตฌ์กฐ์ฒด๊ฐ ๋ ์ ์๋ค๋ ๊ฒ์ ์๊ฐํ๋ฉด์, ๊ทธ๋ ๋ค๋ฉด ์ ๋ค๋ฆญ ํ์ ์ด ์ด๋ค ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด์ผ๋ง ์ฌ์ฉ๋ ์ ์๋์ง๋ฅผ ๊ณ ๋ คํด์ ํธ๋ ์ดํธ ๊ตฌํ์ where๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผํฉ๋๋ค. ์ ์ฐจ where์ Copy๋ฑ์ ๋ง์ปค ํธ๋ ์ดํธ๊ฐ ์์ด์ ๋น๋๊ฐ ์๋๋ ๊ฒ์ ๊ฒฝํํ์ค ๊ฒ๋๋ค. ๊ทธ๋ ๊ฒ ๋ง์ปค ํธ๋ ์ดํธ์ ์ด๋ค ๊ฒ๋ค์ด ์๋์ง, ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ๋ฑ์ ์กฐ๊ธ์ฉ ๊ฒฝํํ๋ฉด์ ํธ๋ ์ดํธ์ ์ ๋ค๋ฆญ์ ๋ํด์ ๋ ์ ์ดํดํ๊ฒ ๋ ๊ฒ์ ๋๋ค.
- ๋น์ฐํ ๊ฐ์ฒด์งํฅ์ ๋ํ ์ดํด๊ฐ ์๋ค๋ฉด ๋ ๋นจ๋ฆฌ ์ต์ํด์ง์ค ์ ์์ต๋๋ค. ํ์ค์ผ๋ฑ ์์ ๊ฐ์ฒด์งํฅ ์ธ์ด๋ฟ ์๋๋ผ ๊ฐ์ฒด์งํฅ ์ค๊ณ์ ๋ํ ์ฑ ๋ค๋ ์ฝ์ด๋ณด์ธ์. ๊ทธ๋ฆฌ๊ณ ํจ์ํ ์ธ์ด์ ์ค๊ณ์ ๋ํด์๋ ๊ฒฝํํด๋ณด๋ฉด ๋ฌ์คํธ ์ธ์ด๋ฅผ ์ฌ์ฉํ๋๋ฐ ๋์์ด ๋ฉ๋๋ค. ์ ๋ Scala์ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ๋ํ ์จ๋ผ์ธ ์์ ์ ๋ฃ๊ณ , Structure and Interpretation of Computer Programs๋ผ๋ Scheme์ธ์ด์ ๊ดํ ์ฑ ์ ์ฐ์ต๋ฌธ์ ๋ฅผ ํ์ด๋ณด๋ฉด์, ํจ์ํ ์ธ์ด์ ์ค๊ณ์ ๋ํด์ ๊ณต๋ถํ์์ต๋๋ค.
๋ฌ์คํธ์ Result, Option์ ๋ฐฐ์ฐ๋ฉด ์ฒ์์๋ ๋ณดํต ๋ค์๊ณผ ๊ฐ์ด ์๋ฌ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ๋ฉ๋๋ค.
fn check_command(cmd: &str) -> Result<usize, String> {
match cmd {
"good" => Ok(0),
"unsupported" => Err("Unsupported command".to_owned()),
"bad" => Err("Bad command".to_owned()),
_ => Err("Wierd command".to_owned()),
}
}
fn handle_command(cmd: &str) -> Result<usize, String> {
// use unwrap
let passed = check_command(cmd).unwrap();
println!("first check passed: status={}", passed);
// check Result
let failed = check_command(cmd);
if failed.is_ok() {
println!("Second check passed: status={}", failed.unwrap());
} else if failed.is_err() {
println!("Second check failed: status={:?}", failed);
}
// use pattern
match check_command(cmd) {
Ok(s) => println!("Third check passed:{}", s),
Err(s) => println!("Error={}", s),
}
Ok(0)
}
fn main() {
let status = handle_command("good");
if status.is_ok() {
println!("Everything is fine");
} else {
println!("I don't feel good");
}
}
์์ ์ ์๋ check_commandํจ์์ handle_command ํจ์๋ Result๋ฅผ ๋ฐํํฉ๋๋ค. ํจ์๊ฐ ์คํ์ ์ฑ๊ณตํ์๋์ ๋ฐํ๊ฐ์ usizeํ์ ์ด๊ณ , ์คํจํ์ ๋๋ Stringํ์ ์ผ๋ก ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๋ฐํํฉ๋๋ค. ์ด๋ ๊ฒ Resultํ์ ์ผ๋ก ์ป์ ๋ฐํ๊ฐ์ ์ฒ๋ฆฌํ ๋ ์ฃผ๋ก 3๊ฐ์ง ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ฒ ๋๋๋ฐ
- unwrap ๋ฉ์๋ ํธ์ถ
- is_ok, is_err๋ฑ ๋ฐํ๊ฐ์ ํ์ธํ๋ ๋ฉ์๋ ํธ์ถ
- match๋ฅผ ์ด์ฉํ ํจํด ๋งค์นญ์ผ๋ก ๋ฐํ๊ฐ์ ๊บผ๋ด์ ํ์ธ
Resultํ์ ์ ์ฌ์ฉํ๋ค๋ณด๋ฉด ๋ด๊ฐ ์ํ๋ ๊ฐ์ Resultํ์ ์ ๋ด๋ถ์ ๊ฐ์ธ์ฌ์ง ๊ฐ์ด๊ธฐ ๋๋ฌธ์ ๊ทธ ๊ฐ์ ํญ์ ๊บผ๋ด์ผ ํ๋ค๋๊ฒ ๋ถํธํฉ๋๋ค. ๊ทธ๋์ ๋ณดํต ์ฒ์ ๋ฌ์คํธ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ํ๋กํ ํ์ ์ ๋ง๋ค์ด๋ณด๋ ๊ฒฝ์ฐ์ unwrap์ ๋ง์ด ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ unwrap์ ์น๋ช ์ ์ธ ๋จ์ ์ด ์์ด์ ์์ฃผ ์ด๊ธฐ๋จ๊ณ ํ๋กํ ํ์ ์ ์์ฑํ ๋๋ ์ฌ์ฉํ์ง ์ค์ ์๋น์ค์ ๋ค์ด๊ฐ๋ ์ฝ๋์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐ๋ก ํ๋ก๊ทธ๋จ์ ํจ๋์ ์ผ์ผํค๊ณ ์ฃฝ๋๋ค๋ ๊ฒ์ ๋๋ค. ์๋ฌ๋ฅผ ์ ๋๋ก ์ฒ๋ฆฌํ์ง์๊ณ ์ฃฝ๊ธฐ๋ง ํ๋ ์ฝ๋๋ ์ ํ์ ์ฌ์ฉํ ์๊ฐ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด์จ๋ ๋ฐํ๊ฐ์ด ์๋ฌ์ธ์ง ์๋์ง๋ฅผ ํ์ธํด์ผํ๊ธฐ ๋๋ฌธ์ is_ok, is_err ๋ฑ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, ๋งคํด ๋งค์นญ์ ์ฌ์ฉํด์ Result์์ ์๋ ๊ฐ์ ๊บผ๋ด์ ์ฌ์ฉํฉ๋๋ค. ์ฌ์ค ์ด๋ฌ๋ฉด check_command์์ ์ด๋ฏธ ํ๋ฒ ์ฒดํฌํ ์๋ฌ๋ฅผ handle_command ํจ์์์ ๋ ๋ค์ ์ฒดํฌํ๋ ๊ผด์ ๋๋ค. ๋ถํ์ํ ์๋ฌ ์ฒดํฌ๊ฐ ๋๋ฌด ๋ง์์ง๋๋ค. handle_command ํจ์๋ ์๋ฌ๋ฅผ ์ฒดํฌํ๋ ค๋ ํจ์๊ฐ ์๋๋ผ, ์ ์์ ์ธ ์ํฉ์์ ์ฒ๋ฆฌ๋ฅผ ํ๋๊ฒ ์ฃผ ๋ชฉํ์ธ ํจ์์ด๊ณ , ๋ง์ฝ ์๋ฌ๊ฐ ๋ฌ์ผ๋ฉด ๋ฐ๋ก ์๋ฌ ๊ฐ์ ์์ ํจ์๋ก ๋ฐํํ๊ธฐ๋ง ํ๋ฉด ๋๋ ํจ์์ ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ ๊ฒ ์๋ฌ ์ฒดํฌ๋ฅผ ์ผ์ผ์ด ๋ค์ ํ ํ์๊ฐ ์์ง์.
์กฐ๊ธ๋ ๋ฌ์คํธ ์ธ์ด๋ค์ด(์์ด๋ก๋ Rusty๋ผ๊ณ ํฉ๋๋ค. ์ง์ญ์ ํ๋ฉด ๋ น์ด ์ฌ์๋ค๋ ๋ป์ ๋๋ค.) ์๋ฌ ์ฒ๋ฆฌ ์ฝ๋๋ฅผ ํ๋ฒ ๋ณด๊ฒ ์ต๋๋ค. ๋ฌผ๋ก ์ผ๋ฐ์ ์ธ ๊ฒ์ด๊ณ ๋ชจ๋ ํ๋ก์ ํธ๊ฐ ์ด๋ ๊ฒ ํ๋ค๋ ๊ฒ์ ์๋๋๋ค. ํ์ง๋ง ๋ฌ์คํธ ์ธ์ด์์ ๊ถ์ฅํ๋ ์๋ฌ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ ํ๋ฒ ๋ณด๊ณ ๋๋ฉด ๋ฌ์คํธ๊ฐ ์ถ๊ตฌํ๋ ์๋ฌ์ ๋ํ ์ ์ฑ ๊ณผ Result/Option ๋ฑ์ ์ค๊ณ ์ฒ ํ์ ๋ ์ ์ดํดํ์ค ์ ์์ ๊ฒ์ ๋๋ค.
์ฒซ๋ฒ์งธ๋ก ๋ด ํ๋ก์ ํธ ์ ๋ฐ์์ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉํ ์๋ฌ ํ์ ์ ํ๋ ๋ง๋ค๊ณ Resultํ์ ์ ์ฌ์ ์ํฉ๋๋ค. ์์ผ๋ก ํ๋ก๊ทธ๋จ์์ ์ฌ์ฉํ ๋ชจ๋ Result ํ์ ์์ ์๋ฌ๋ MyError๋ผ๋ ํ์ ๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค.
#[derive(Debug, PartialEq)]
pub enum MyError {
UnsupportedCommand,
WrongInput(String),
UnknownValue {
name: String,
expected: String,
found: String,
},
// Add more error cases
}
pub type Result<T, E = MyError> = std::result::Result<T, E>;
๋จผ์ ๋ด ํ๋ก์ ํธ์์ ๋ฐ์ํ ์ ์๋ ์๋ฌ๋ค์ ์๊ฐํด์ ๊ฐ ์๋ฌ๋ง๋ค ๋ณ๋์ ํ์ ์ ๋ง๋ค์ด์ฃผ๊ณ , ๊ฐ ํ์ ๋ง๋ค ์ด๋ค ์ ๋ณด๋ฅผ ๋ฃ์ด์ค ๊ฒ์ธ์ง๋ฅผ ์๊ฐํด์ MyError๋ผ๋ ์๋ก์ด ํ์ ์ ๋ง๋ค์ด์ค๋๋ค. ์์ ์์ ์์๋ command์ฒ๋ฆฌ์ ์์ด์ 3๊ฐ์ง ๊ฒฝ์ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก ๊ฐ๊ฐ์ ๊ฒฝ์ฐ์ ๋ฐ๋ฅธ ์๋ฌ ๊ฐ์ ๋ง๋ค์ด์คฌ์ต๋๋ค.
- UnsupportedCommand: ๋ช ๋ น์ด๊ฐ ์ง์๋์ง ์๋ ๊ฒฝ์ฐ๋ ์ถ๊ฐ์ ์ธ ๋ฐ์ดํฐ๋ ์๋ ์๋ฌ ๊ฐ์ ๋ง๋ค์ด์ค๋๋ค.
- WrongInput(String): ์๋ชป๋ ์ ๋ ฅ์ ๊ฒฝ์ฐ ์ด๋ค ์ ๋ ฅ์ด ์๋ชป๋์๋์ง๋ฅผ ์๋ฌ ๋ฉ์ธ์ง๋ก ์๋ ค์ฃผ๊ธฐ ์ํด String ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๋ ์๋ฌ ๊ฐ์ ๋ง๋ค์ด์ค๋๋ค.
- UnknownValue{โฆ}: ์ด ์๋ฌ๋ ์ฌ์ฉ์์๊ฒ ์ข ๋ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ธฐ ์ํด ๊ตฌ์กฐ์ฒด์ ๊ฐ์ด ์ฌ๋ฌ ํ๋๋ฅผ ํฌํจํ๋ ์๋ฌ ํ์ ์ ๋๋ค.
์ด๋ ๊ฒ ์๋ฌ ํ์ ์ ๋ฐ๋ผ ๋ค์ํ ์ ๋ณด๋ฅผ ๋ฃ์ด์ค ์ ์์ผ๋ ๋๋ฌด๋ ํธ๋ฆฌํด์ง๋๋ค. ๊ฒฝ์ฐ์ ๋ฐ๋ผ ์๋ก ๋ค๋ฅธ ํ์ ์ ๋ฐ์ดํฐ์ ๋ณ๋๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ฝ๋๊ฐ ๋ณต์กํด์ง ํ์๊ฐ ์์ต๋๋ค. MyError๋ผ๋ ํ์ ํ๋๋ง์ผ๋ก ๋ชจ๋ ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉด์๋, ๊ฐ ์๋ฌ ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ์ ๋ณด๋ฅผ ๋ฃ์ด์ ๊ด๋ฆฌํ ์ ์์ผ๋ ์๋ฌ ์ฒ๋ฆฌ ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๋๋ค. ๋ํ ๋ฌ์คํธ์์ ํญ์ ๋ชจ๋ ์๋ฌ๋ฅผ ๋ค ์ฒ๋ฆฌํด์คฌ๋์ง๋ฅผ ์ฒดํฌํด์ฃผ๋ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ๋นผ๋๋ ์ผ์ ๋ง์ ์ ์์ต๋๋ค. ํ๋ก์ ํธ๊ฐ ์ปค์ง๊ฑฐ๋ ๊ฐ๋ฐ์ ํด๋๊ฐ๋ฉด์ ์ข ๋ ๋ค์ํ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ๋น์ฐํ MyError์ ์๋ก ์ถ๊ฐ๋ ๋ฐ์ดํฐ ํ์ ์ ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
๋ด๊ฐ ๋ง๋ ํจ์์์๋ MyError๋ฅผ ๋ฐํํ ์ ์์ง๋ง, ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ์ป๊ฒ๋๋ ๋ค๋ฅธ ํ์ ์ ์๋ฌ๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌํด์ผํ ๊น์? ๊ทธ๋ด๋๋ ์๋์ ๊ฐ์ด ์๋ฌ์ ํ์ ์ ๋ฐ๊ฟ์ฃผ๋ฉด ๋ฉ๋๋ค. ์ด ํจ์๋ฅผ ํธ์ถํ๋ ์์ ํจ์๋ MyError ํ์ ๋ง์ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค.
let mut file = match File::open(&path) {
Err(why) => MyError::WrongInput(format!("Cannot open the file {}, because {}", path, why),
Ok(file) => file,
};
๊ทธ๋ผ ์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋ ์๋ก์ด ์๋ฌ ํ์ ์ ์ด๋ป๊ฒ ์ฌ์ฉํ ๊น์. check_command ํจ์์ ์๋ก์ด ์๋ฌ ํ์ ์ ์ ์ฉํด๋ดค์ต๋๋ค.
// fn check_command(cmd: &str) -> Result<usize, String> {
fn check_command(cmd: &str) -> Result<usize> {
match cmd {
"good" => Ok(0),
"unsupported" => Err(MyError::UnsupportedCommand),
"bad" => Err(MyError::WrongInput(format!(
"Cannot handle the command:{}",
cmd
))),
_ => Err(MyError::UnknownValue {
name: "Wierd Command Error".to_owned(),
expected: "good".to_owned(),
found: cmd.to_owned(),
}),
}
}
๋ด ํ๋ก์ ํธ์์ ์ฌ์ฉํ ์๋ฌ ํ์ ์ ๋ง๋ค๊ณ , ์ด ์๋ฌ ํ์ ์ ์ฌ์ฉํ Result๋ฅผ ์ฌ์ ์ํ๊ณ ๋๋ฉด check_commandํจ์์ ๊ฐ์ด ํจ์์ ๋ฐํ๊ฐ์ด ๋จ์ํด์ง๋๋ค. ์๋๋ Result<usize, String>๊ณผ ๊ฐ์ด ์ ์ ์ํฉ์ผ๋์ ๋ฐํ๊ฐ ํ์ ๊ณผ ์๋ฌ ์ํฉ์์์ ๋ฐํ๊ฐ ํ์ ์ ๊ฐ์ด ์จ์ค์ผํ์ง๋ง, Result๋ฅผ ์ฌ์ ์ํ๊ณ ๋๋ฉด ์ ์ ์ํฉ์์์ ๋ฐํ๊ฐ ํ์ ๋ง ๊ธฐ๋กํด์ฃผ๋ฉด ๋ฉ๋๋ค. ์๋ฌ ์ํฉ์์์ ๋ฐํ๊ฐ ํ์ ์ ์๋ฌต์ ์ผ๋ก ๋ด๊ฐ ์ ์ํ ์๋ฌ ํ์ ์ด ๋๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ handle_commandํจ์์์๋ ?์ฐ์ฐ์(try์ฐ์ฐ์)๋ฅผ ์ฌ์ฉํ ์๋ ์๊ณ , map_err ๋ฑ์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
pub fn handle_command(cmd: &str) -> Result<usize> {
// use ? operator if it doesn't need to check the error value in this function
let passed = check_command(cmd)?;
println!("Good command passed: status={}", passed);
let _ = check_command(cmd)
.map_err(|e| println!("Command failed: error={:?}", e))
.map(|s| println!("Command passed: status={}", s));
if let Ok(status) = check_command(cmd) {
println!("wierd but ok: status={:?}", status);
} else {
println!("Command failed: command={}", cmd);
}
Ok(0)
}
๋ง์ฝ ๋ด ํ๋ก์ ํธ์ ๊ท๋ชจ๊ฐ ์ปค์ ธ์ ์ฌ๋ฌ ํ์ ๋ชจ๋๋ก ๋๋ ์ง๊ณ ๊ฐ ๋ชจ๋๋ณ๋ก ์๋ฌ ํ์ ์ ๋๋ ์ผํ ํ์๊ฐ ์๊ธฐ๋ฉด ํ์ ๋ชจ๋๋ง๋ค ์๋ฌ ํ์ ์ ๊ฐ์ง๊ณ ์์ ๋ชจ๋์ ํ์ ๋ชจ๋์ ์๋ฌ๋ฅผ ์ฌ์ฉํ๋๋ก ๋ง๋ค๋ฉด ๋ฉ๋๋ค. ์๋ฌ ํ์ ๋ค๋ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ฒ๋๋ฏ๋ก ํ๋ก์ ํธ๋ฅผ ๋ชจ๋๋ก ๋๋๋๊ฒ ๋ ํธ๋ฆฌํด์ง๋๋ค.
์๋๋ handle_command ํจ์๋ฅผ mycommand.rs๋ก ์ฎ๊ธฐ๊ณ handle_command๋ฅผ ํธ์ถํ๋ super_handle_command์ main.rs์ ๋ง๋ค์ด์ค ๊ฒ์ ๋๋ค.
// src/error/mycommand.rs
#[derive(Debug, PartialEq)]
pub enum MyError {
UnsupportedCommand,
WrongInput(String),
UnknownValue {
name: String,
expected: String,
found: String,
},
// Add more error cases
}
pub type Result<T, E = MyError> = std::result::Result<T, E>;
// fn check_command(cmd: &str) -> Result<usize, String> {
fn check_command(cmd: &str) -> Result<usize> {
match cmd {
"good" => Ok(0),
"unsupported" => Err(MyError::UnsupportedCommand),
"bad" => Err(MyError::WrongInput(format!(
"Cannot handle the command:{}",
cmd
))),
_ => Err(MyError::UnknownValue {
name: "Wierd Command Error".to_owned(),
expected: "good".to_owned(),
found: cmd.to_owned(),
}),
}
}
pub fn handle_command(cmd: &str) -> Result<usize> {
// use ? operator if it doesn't need to check the error value in this function
let passed = check_command(cmd)?;
println!("Good command passed: status={}", passed);
let _ = check_command(cmd)
.map_err(|e| println!("Command failed: error={:?}", e))
.map(|s| println!("Command passed: status={}", s));
if let Ok(status) = check_command(cmd) {
println!("wierd but ok: status={:?}", status);
} else {
println!("Command failed: command={}", cmd);
}
Ok(0)
}
// src/error/main.rs
mod mycommand;
use crate::mycommand::*;
#[derive(Debug, PartialEq)]
pub enum SuperError {
CommandError(MyError),
}
pub type Result<T, E = SuperError> = std::result::Result<T, E>;
impl From<MyError> for SuperError {
fn from(err: MyError) -> Self {
Self::CommandError(err)
}
}
fn super_handle_command(cmd: &str) -> Result<usize> {
Ok(mycommand::handle_command(cmd)?)
}
fn main() {
let status: Result<usize, SuperError> = super_handle_command("bad");
if status.is_ok() {
println!("Everything is fine");
} else {
println!("I don't feel good:{:?}", status);
}
}
$ cargo run --bin error
Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/error`
I don't feel good:Err(CommandError(WrongInput("Cannot handle the command:bad")))
main ๋ชจ๋์ mycommand.rs ๋ชจ๋์ ์๋ฌ ํ์ ์ ํฌํจํ๋ ์๋ก์ด ์๋ฌ ํ์ SuperError๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ SuperError ํ์ ์ ์ํ From ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๋๋ค. handle_command์์ ๋ฐํ๋ MyErrorํ์ ์ด ์๋์ผ๋ก SuperError๋ก ๋ณํ๋์ mainํจ์๋ก ์ ๋ฌ๋ ์ ์์ต๋๋ค. ๋ง์ฝ MyError์ด์ธ์ ๋๋ค๋ฅธ ํ์ ์๋ฌ ํ์ ์ด ์๊ธฐ๋ฉด From<์๋ก์ด ํ์ ๋ชจ๋์ ์๋ฌ ํ์ > ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ฉด ๋ฉ๋๋ค.
mainํจ์์์ ์๋ฌ ๊ฐ์ด ์ถ๋ ฅ๋ ๊ฒ์ ๋ณด๋ฉด ์์ ์๋ฌ ํ์ SuperError์์ ํ์ ์๋ฌ ํ์ MyError๊ฐ ์ ์ฅ๋์ด์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
super_handle_commandํจ์๋ ๋จ ํ์ค์ด์ง๋ง ์ฌ์ค์ ์๋ณด์ด๋ ๋ช๊ฐ์ง ๋์์ด ์จ์ด์ ธ ์์ต๋๋ค.
fn super_handle_command(cmd: &str) -> Result<usize> {
Ok(mycommand::handle_command(cmd)?)
}
mycommand::handle_command๊ฐ ์ฑ๊ณตํ์ ๊ฒฝ์ฐ
- ?์ฐ์ฐ์๋ usize๊ฐ์ ๊บผ๋ด์ค.
- super_handle_command๋ Ok(์ฑ๊ณตํ ๊ฒฐ๊ณผ๊ฐ)์ ๋ฐํํ๊ฒ๋จ
mycommand::handle_command๊ฐ ์๋ฌ๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ
- ?์ฐ์ฐ์๋ MyErrorํ์ ์ ์๋ฌ๋ฅผ super_handle_command์ ๋ฐํ๊ฐ์ผ๋ก ๋๊ธฐ๋ ค๊ณ ์๋ํจ
- SuperError์ From ํธ๋ ์ดํธ์ ์ํด MyError๊ฐ SuperError::CommandError๋ก ๋ณํ๋จ
- super_handle_command์ ์ต์ข ์ ์ธ ๋ฐํ๊ฐ์ SuperError::CommandError๊ฐ ๋จ
๋ผ์ดํํ์์ Dangling reference(์ ํจํ์ง ์์ ์ฐธ์กฐ, ์ด๋ฏธ ํด์ง๋ ๊ฐ์ฒด์ ๋ํ ํฌ์ธํฐ์ ์ ๊ทผํ๋ ๊ฒฝ์ฐ)๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํ ๊ธฐ๋ฒ์ ๋๋ค. ์์ํ๋ ๋จ๊ณ์์ ๋ผ์ดํํ์์ ์ธ์ธํ๊ฒ ์ค์ ํ๋ ์ผ์ ๊ฑฐ์ ์์ต๋๋ค. ๊ทธ๋์ ์์ธํ ์ค๋ช ์ ๋ฌ์คํธ ์ธ์ด์ ํ์ค ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์๊ธธ ๋ฐ๋ผ๊ณ ์ด ์ฅ์์๋ ํต์ฌ๋ง ์ด์ผ๊ธฐํ๊ฒ ์ต๋๋ค. ์ฌ์ค ๋ผ์ดํํ์์ ๊ฐ๋ ์ ์ ์ดํดํ๋ค๊ณ ํด๋ ์ค์ ๋ก ๊ฐ๋ฐ์ ํ๋ค๋ณด๋ฉด ๋ผ์ดํํ์๊ณผ ๊ด๋ จ๋ ๋น๋ ์๋ฌ๋ฅผ ์์ฃผ ๊ฒช์ผ์ค ๊ฒ์ ๋๋ค. ๊ทธ๋ด๋๋ ์ปดํ์ผ๋ฌ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ์ต๋ํ ํ์ฉํ๋๊ฒ ํ์ํฉ๋๋ค.
๋ผ์ดํํ์์ ๋๋ถ๋ถ ์๋์๊ฐ์ด ์ด๋ค ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค๊ณ , ๊ทธ ๊ตฌ์กฐ์ฒด์ ์ผ๋ถ๋ ์ ์ฒด๋ฅผ ๋ค๋ฅธ ๊ตฌ์กฐ์ฒด์์ ์ฐธ์กฐํ๋ ๊ฒฝ์ฐ์ ํ์ํฉ๋๋ค.
// src/lifetime/main.rs
use std::collections::HashMap;
struct Item {
name: String,
price: f32,
quantity: u32,
}
struct Storage {
items: HashMap<String, Item>,
}
impl Storage {
fn new() -> Self {
Storage {
items: HashMap::new(),
}
}
fn storage_store(&mut self, item: Item) {
self.items.insert(item.name.clone(), item);
}
}
struct Statistics<'a> {
items: &'a HashMap<String, Item>,
}
impl<'a> Statistics<'a> {
fn new(items: &'a HashMap<String, Item>) -> Self {
Statistics { items }
}
fn get_average(&self) -> f32 {
let total = self.items.values().fold(0.0, |acc, i| acc + i.price);
let count = self.items.values().fold(0, |acc, i| acc + i.quantity);
total / count as f32
}
}
fn main() {
let mut mystorage = Storage::new();
let apple = Item {
name: "apple".to_string(),
price: 1.0,
quantity: 10,
};
mystorage.storage_store(apple);
let banana = Item {
name: "banana".to_string(),
price: 2.0,
quantity: 20,
};
mystorage.storage_store(banana);
let stats = Statistics::new(&mystorage.items);
println!("{}", stats.get_average());
}
Storage๋ ์ฐฝ๊ณ ์ ์ ์ฅ๋ ๊ณผ์ผ์ ๊ฐฏ์์ ๊ฐ๊ฒฉ์ ๊ด๋ฆฌํฉ๋๋ค. ๋ค์๊ณผ ๊ฐ์ด ๊ณผ์ผ ์ด๋ฆ์ ํค๋ก ๊ฐ๊ณ , ๊ณผ์ผ์ ๋ํ ์ ๋ณด Item๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ์ผ๋ก ๊ฐ๋ ํด์ฌ๋งต์ ๋๋ค.
{
"apple": Item {name: "apple", price: 1.0, quantity: 1.0},
"banana": Item {name: "banana", price: 2.0, quantity: 20}
}
Statistics๋ ๊ฐ๊ฐ์ ์ฐฝ๊ณ ์ ์๋ ๊ณผ์ผ ๊ฐ๊ฒฉ์ ๋ํ ํต๊ณ๋ฅผ ๊ณ์ฐํ๋ ์ผ์ ํฉ๋๋ค. ์์ ์ฝ๋๋ ์ ํํ ํต๊ณ๋ฅผ ๋ง๋๋๊ฑด ์๋๊ณ , ๊ทธ๋ฅ ์์ ๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์๋ฌด๋ฐ ์๋ฏธ์๋ ๊ณ์ฐ์ ํฉ๋๋ค. get_averageํจ์๊ฐ ๊ทธ๋ฐ ๊ณ์ฐ์ ํ๋ ํจ์์ ๋๋ค.
fn get_average(&self) -> f32 {
let total = self.items.values().fold(0.0, |acc, i| acc + i.price);
let count = self.items.values().fold(0, |acc, i| acc + i.quantity);
total / count as f32
}
๋จ๊ณ๋ณ๋ก ์ค๋ช ์ ํด๋ณด๋ฉด
- items๋ Storage๊ฐ ๊ฐ์ง๊ณ ์๋ items์ ๋ ํผ๋ฐ์ค์ ๋๋ค
- items.values()๋ ํด์ฌ๋งต์ ์๋ ๋ชจ๋ ๊ฐ์ ๋ํ ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ฐํํฉ๋๋ค
- ์ดํฐ๋ ์ดํฐ์ fold๋ฉ์๋๋ ์ด๊ธฐ๊ฐ 0์ ๊ฐ๊ณ , items๋ผ๋ ํด์ฌ๋งต์ ๊ฐ ๊ฐ๋ค์์ price ๊ฐ๋ค์ ์ฝ์ด์ acc ๋ณ์์ ๋์ ํด์ ๋ํฉ๋๋ค. acc๋ ์ต์ข ์๋ ๋ชจ๋ ๊ณผ์ผ๋ค์ ๊ฐ๊ฒฉ์ ๋ค ํฉ์น ๊ฐ์ด ๋๊ณ total์ ์ ์ฅ๋ฉ๋๋ค.
- ๋ง์ฐฌ๊ฐ์ง๋ก count์๋ ๋ชจ๋ ๊ณผ์ผ๋ค์ ๊ฐฏ์๋ฅผ ๋ค ํฉ์น ๊ฐ์ด ์ ์ฅ๋ฉ๋๋ค.
- get_average๋ total์ count๋ก ๋๋ ๊ฐ์ ๋ฐํํฉ๋๋ค.
์ฌ์ค ๊ณ์ฐ์์ ์๋ฏธ๋ ์ค์ํ์ง ์์ต๋๋ค. ๋จ์ง Storage๋ผ๋ ๊ฐ์ฒด์ ํ๋๋ฅผ Statistics๋ผ๋ ๊ฐ์ฒด๊ฐ ๋ ํผ๋ฐ์ค๋ก ๊ฐ์ง๊ณ ์๋๊ฒ ์ค์ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ Statistics๊ฐ ๋ ํผ๋ฐ์ค๋ฅผ ๊ฐ์ง๊ณ ์๋ Storage ๊ฐ์ฒด๊ฐ Statistic๋ณด๋ค ๋จผ์ ํด์ง๋๋ฉด ์๋๋ค๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
struct Statistics<'a> {
items: &'a HashMap<String, Item>,
}
impl<'a> Statistics<'a> {
fn new(items: &'a HashMap<String, Item>) -> Self {
Statistics { items }
}
Statistics ๊ฐ์ฒด๋ฅผ ์ ์ธํ ๋, &Hashmap๊ณผ ๊ฐ์ด ๋ ํผ๋ฐ์ค๋ฅผ ์ฌ์ฉํ๋๊ฒ ์๋๋ผ &'a HashMap์ผ๋ก ๋ฌํผ๋ฐ์ค ๊ธฐํธ์ 'a๋ผ๋ ์ด๋ฆ์ ์ง์ ํด์ฃผ์์ต๋๋ค. ๊ทธ๋์ items๋ผ๋ ๋ ํผ๋ฐ์ค์ ์๋ช ์ด a๋ก ์ง์ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ newํจ์์์ ์ ๋ฌ๋ฐ์ ๋ ํผ๋ฐ์ค๊ฐ ๋ฐ๋ก ์๋ช ์ด๋ฆ a๋ก ์ ์ฅํ๋ ๋ ํผ๋ฐ์ค์ ๋๋ค.
Statistics ์๊ธฐ ์์ ๋ณด๋ค Statistics๊ฐ ๊ฐ์ง๊ณ ์๋ ๋ ํผ๋ฐ์ค๊ฐ ๋ ๊ธด ์๋ช (๋ ๋์ค์ ๊ฐ์ฒด๊ฐ ํด์ง๋์ด์ผํจ)์ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค. ๊ทธ๋์ ๋ฌ์คํธ ์ปดํ์ผ๋ฌ๋ Statistics๊ฐ ๊ฐ์ง๊ณ ์๋ ๋ ํผ๋ฐ์ค์ ์๋ช ์ด๋ฆ๋ค์ ๊ฐ์ง๊ณ , Statistics๊ฐ ์ฐธ์กฐํ๋ ๊ฐ์ฒด๋ค ์ค ์ด๋ ํ์ชฝ์ด Statistics ๊ฐ์ฒด๋ณด๋ค ๋จผ์ ํด์ง๋์ง ์๋๋ก ๊ฐ์ํ ์ ์์ต๋๋ค.
์ง๊ธ๊น์ง ๋ ํผ๋ฐ์ค๋ฅผ ์ฌ์ฉํ ๋๋ง๋ค ์๋ช ์ ์ง์ ํ์ง ์์ ์ด์ ๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ฝ๋๊ฐ ๊ฐ๋จํด์ ๋ฌ์คํธ ์ปดํ์ผ๋ฌ๊ฐ ์๋ช ์ ์ง์ ํ๋จํ ์ ์์๊ธฐ ๋๋ฌธ์ ๋๋ค. ํ์ง๋ง ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ณ , ์ฌ๋ฌ ๊ฐ์ฒด๋ค์ด ์๋ก๋ฅผ ์ฐธ์กฐํ๊ฒ๋๋ฉด ๋ฌ์คํธ ์ปดํ์ผ๋ฌ๊ฐ ์๋ช ์ ํ๋จํ ์ ์๊ฒ๋๊ณ , ๊ฐ๋ฐ์์๊ฒ ์๋ช ์ ์ง์ ํ๋๋ก ์๊ตฌํ ๊ฒ์ ๋๋ค. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ปดํ์ผ๋ฌ์ ์๋ฌ ๋ฉ์ธ์ง๋๋ก ๋ฐ๋ฅด๊ธฐ๋งํ๋ฉด ๋น๋๋ ๋์์ ๋ฌธ์ ๊ฐ ์์ ๊ฒ์ ๋๋ค.