ํธ๋ ์ดํธ๋ ์ด๋ค ํ์ ์ด๋ ์๊ด์์ด ๊ณตํต๋ ๋์์ ํ๋๋ก ์ง์ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด ์๋ก ๋ค๋ฅธ ํ์ ์ ๊ฐ์ฒด๋ค์ด๋ผ๊ณ ํด๋ ๊ฐ์ ํธ๋ ์ดํธ์ ๊ตฌํํ๋๋ก ๋ง๋ค๋ฉด ๊ฒฐ๊ตญ ๊ณตํต๋ ํน์ง์ ๊ฐ๋๋ก ๋ง๋ค ์ ์์ต๋๋ค. ํจ์ ์ธ์๋ก ๊ฐ์ฒด๋ฅผ ๋๊ธธ ๋, ํ์ ์ ์ง์ ํ๋๊ฒ ๋ณดํต์ด์ง๋ง, ํน์ ํ ํธ๋ ์ดํธ์ ๊ตฌํํ ํ์ ์ด๋ฉด ๋ฌด์์ด๋ ์ง ์ ๋ฌํ ์๋ ์๊ฒ ๋ฉ๋๋ค. ํจ์ ์ธ์์ ๊ตฌ์กฐ์ฒด ์ด๋ฆ์ด ์๋๋ผ, ์ด๋ค ํธ๋ ์ดํธ์ ์ด๋ฆ์ ์ธ ์๋ ์์ต๋๋ค.
๋ค๋ฅธ ๊ฐ์ฒด์งํฅ ์ธ์ด๋ฅผ ๊ฒฝํํด๋ดค๋ค๋ฉด ์ถ์ ํด๋์ค๋ ์ธํฐํ์ด์ค์ ๋น์ทํ ๊ฒ์ด๋ผ๊ณ ์ดํดํด๋ ์ข์ต๋๋ค. ๋ค์ํ ํ์ ์ ๊ฐ์ฒด๋ค์ ๋ฌถ๋ ์ถ์ํ๋ฅผ ํ ์ ์๊ธฐ๋ ํ๊ณ , ์ฝ๋๋ฅผ ์ฌ์ฌ์ฉํ ์๋ ์๋ ๋ฑ ๋ฌ์คํธ๋ก ๊ท๋ชจ์๋ ํ๋ก๊ทธ๋จ์ ๋ง๋ค๊ธฐ ์ํด์๋ ํ์์ ์ผ๋ก ์ ํ์ฉํ ์ ์์ด์ผ๋๋ ๋ฌธ๋ฒ์ ๋๋ค.
์์ฃผ ๊ฐ๋จํ ์์ ๋ฅผ ๊ฐ์ง๊ณ ์์ํด๋ณด๊ฒ ์ต๋๋ค. ๋ค์ ์์ ๋ ์๋ก ๋ค๋ฅธ ๋ ๊ตฌ์กฐ์ฒด Person๊ณผ Book์ ๊ณตํต์ ํธ๋ ์ดํธ Printable์ ๊ตฌํํ๋ ์์ ์ ๋๋ค.
// src/trait/main.rs
trait Printable {
type Age;
fn print(&self);
fn get_age(&self) -> 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 for Person {
type Age = u32;
fn print(&self) {
println!("Name: {}, {} years old", self.name, self.get_age());
}
fn get_age(&self) -> Self::Age {
self.age
}
}
struct Book {
title: String,
author: String,
published: u32,
}
impl Printable for Book {
type Age = u32;
fn print(&self) {
println!(
"Title: {}\nAuthor: {}\nPublished: {}",
self.title,
self.author,
self.get_age()
);
}
fn get_age(&self) -> Self::Age {
self.published
}
}
fn print_info(item: &dyn Printable<Age = u32>) {
item.print();
}
fn main() {
let person = Person::new("Alice", 22);
let book = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20230228,
};
print_info(&person);
print_info(&book);
}
$ cargo run --bin trait
Finished dev [unoptimized + debuginfo] target(s) in 0.75s
Running `target/debug/trait`
Name: Alice, 22 years old
Title: The Rust Programming Language
Author: Steve Klabnik and Carol Nichols
Published: 20230228
์ฒซ๋ฒ์งธ๋ก Printable์ด๋ผ๋ ํธ๋ ์ดํธ๋ฅผ ์ ์ธํ๋ ์ฝ๋๊ฐ ๋์ต๋๋ค.
trait Printable {
type Age;
fn print(&self);
fn get_age(&self) -> Self::Age;
}
Printable์ด๋ผ๋ ํธ๋ ์ดํธ์๋ 2๊ฐ์ ํจ์์ 1๊ฐ์ ํ์ ์ด ํฌํจ๋ฉ๋๋ค. ์ด์ ์ด ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ๊ตฌ์กฐ์ฒด๋ค์ 2๊ฐ์ ํจ์๋ฅผ ์ ์ํด์ผํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ Age๋ผ๋ ํ์ ์ ๋ฌด์จ ๋ฐ์ดํฐ ํ์ ์ผ๋ก ์ฌ์ฉํ ๊ฒ์ธ์ง๋ฅผ ์ ํด์ผํฉ๋๋ค. i32๊ฐ์ ๊ธฐ๋ณธ ํ์ ์ ์ฌ์ฉํ ์๋์๊ณ , ์๋ก์ด ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ ์๋์์ต๋๋ค. ๊ทธ๋ฌ๋ ํธ๋ ์ดํธ๋ผ๋ ๊ฒ์ด ๋ฐ๋์ ํน์ ํจ์๋ฅผ ๊ตฌํํ๋๋ก ํ๋ ๊ฒ๋ง์ด ์๋๋ผ, ์ด๋ค ๋ฐ์ดํฐ ํ์ ์ ์ธ์ง๋ ์ ํ ์ ์๋ค๋ ๊ฒ์ ์ฃผ์ํ์๊ธฐ ๋ฐ๋๋๋ค.
๊ทธ๋ฆฌ๊ณ Person ๊ตฌ์กฐ์ฒด๋ฅผ ์ ์ํฉ๋๋ค.
struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: &str, age: u32) -> Self {
Person {
name: name.to_string(),
age: age,
}
}
}
์ฐ์ Personํ์ ์ด ํธ๋ ์ดํธ์ ์๊ด์์ด ๊ฐ์ง๋ Personํ์ ๋ง์ ๊ณ ์ ํ ํจ์ new๋ฅผ ๊ตฌํํฉ๋๋ค. ๊ทธ ๋ค์์ผ๋ก Person์ ์ํด Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํฉ๋๋ค.
impl Printable for Person {
type Age = u32;
fn print(&self) {
println!("Name: {}, {} years old", self.name, self.get_age());
}
fn get_age(&self) -> Self::Age {
self.age
}
}
์ฌ๋์ ๋์ด๋ฅผ ์๋ฏธํ๋ Age๋ผ๋ ํ์ ์ ์ ์ํฉ๋๋ค. ํ์ ์ด๋ฆ์ Age์ด์ง๋ง, ์ฌ์ค์ u32ํ์ ์ ๋ณ์นญ(alias)์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค. ์ฌ๋ ๋์ด๋ ์์๊ฐ ์์ผ๋๊น u32๋ฅผ ์ฌ์ฉํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ print ํจ์์ get_ageํจ์์ ๊ตฌํ์ด ์์ต๋๋ค. printํจ์๋ ์ฌ๋์ ์ด๋ฆ๊ณผ ๋์ด๋ฅผ ํฐ๋ฏธ๋์ ์ถ๋ ฅํฉ๋๋ค. get_ageํจ์๋ Ageํ์ ์ ๋ฐํํด์ผํ๋๊น ๊ฒฐ๊ณผ์ ์ผ๋ก๋ u32ํ์ ์ ๋ฐํํ๋ ๊ฒ์ด ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ Book ๊ตฌ์กฐ์ฒด์ ์ ์์, Book ๊ตฌ์กฐ์ฒด๋ฅผ ์ํ Printable ํธ๋ ์ดํธ์ ๊ตฌํ์ด ๋์ต๋๋ค.
struct Book {
title: String,
author: String,
published: u32,
}
impl Printable for Book {
type Age = u32;
fn print(&self) {
println!(
"Title: {}\nAuthor: {}\nPublished: {}",
self.title, self.author, self.get_age()
);
}
fn get_age(&self) -> Self::Age {
self.published
}
}
Ageํ์ ์ u32๋ก ์ ์ํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ printํจ์์ get_ageํจ์์ ๊ตฌํ์ด ๋์ต๋๋ค. print๋ ์ฑ ์ ์ ๋ชฉ๊ณผ ์ ์, ์ถํ๋ ์ง๋ฅผ ์ถ๋ ฅํฉ๋๋ค. ์ฌ๋์ ์ํ Printable ํธ๋ ์ดํธ์ ์ฑ ์ ์ํ ํธ๋ ์ดํธ๋ ๋์ผํ ์ธํฐํ์ด์ค๋ฅผ ๊ฐ์ง๊ณ ๋ด๋ถ ๋์๋ง ๋ค๋ฆ ๋๋ค.
์ด์ ์ ๋ง ์ค์ํ๊ฒ ๋์ต๋๋ค. ๋ฐ๋ก dyn์ด๋ผ๋ ํค์๋๋ฅผ ์ฐ๋ ํธ๋ ์ดํธ ๊ฐ์ฒด์ ๋๋ค.
fn print_info(item: &dyn Printable<Age = u32>) {
item.print();
}
print_info๋ผ๋ ํจ์์ธ๋ฐ, ์ธ์์ ํ์ ์ด ํน์ดํฉ๋๋ค. dyn์ด๋ผ๋ ํค์๋๊ฐ ์๋ ์ฐธ์กฐ ํ์ ์ ๋๋ค. โdyn Printableโ๋ Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ๋ชจ๋ ํ์ ์ ์ธ์๋ก ๋ฐ๋๋ค๋ ์๋ฏธ์ ๋๋ค. ์ฐธ์กฐ ํค์๋ &๊ฐ ์์ผ๋ฏ๋ก Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ํ์ ์ ์ฐธ์กฐ๋ฅผ ์ธ์๋ก ๋ฐ๋๋ค๋ ๋ป์ด ๋ฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ฃผ์ํ ๊ฒ์ด ํ๋์๋๋ฐ <Age=u32>๋ผ๋ ๊ตฌ๋ฌธ๋ ์์ต๋๋ค. ์ด๊ฒ์ ์๋ฏธ๋ Ageํ์ ์ u32๋ก ์ ์ํ ๊ฐ์ฒด๋ง ์ฐธ์กฐํ๊ฒ ๋ค๋ ๊ฒ์ด ๋ฉ๋๋ค.
์ ๋ฆฌํ์๋ฉด Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ Ageํ์ ์ u32๋ก ์ ์ํ ํ์ ๋ค์ ์ฐธ์กฐ๋ฅผ ์ธ์๋ก ๋ฐ๋ ํจ์์ ๋๋ค. print_infoํจ์๋ฅผ ํธ์ถํ ๋ ์๋ก ๋ค๋ฅธ ํ์ Person๊ณผ Book์ ์ฐธ์กฐ๋ฅผ ์ ๋ฌํ ์ ์๊ฒ๋๋ ์ด์ ๊ฐ ๋ฐ๋ก, Person๊ณผ Book์ด Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ณ , Ageํ์ ์ u32๋ก ์ ์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ง์ฝ Printable ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋คํด๋, Age์ ํ์ ์ด u32์ด ์๋ ๋ค๋ฅธ ํ์ ์ด์๋ค๋ฉด print_infoํจ์์ ์ ๋ฌํ ์ ์์ต๋๋ค.
๋ง์ฝ์ ์ฌ๋ฌ๊ฐ์ ํธ๋ ์ดํธ๋ฅผ ๋ชจ๋ ๋ค ๊ตฌํํ๋ ํ์ ๋ค์ ์ง์ ํ๊ณ ์ถ๋ค๋ฉด ์๋์๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
fn some_function(param: &(dyn Trait1 + Trait2)) {
// Function body
}
Trait1๊ณผ Trait2๋ฅผ ๋ชจ๋ ๊ตฌํํ ํ์ ์ ๋ ํผ๋ฐ์ค๋ฅผ ์ธ์๋ก ๋ฐ๋ ํจ์๊ฐ ๋ฉ๋๋ค.
์ด์๊ฐ์ด dyn ํค์๋๋ฅผ ์ฌ์ฉํ๊ณ ํธ๋ ์ดํธ ์ด๋ฆ์ผ๋ก ๋ํ๋ด๋ ๊ฒ์ ํธ๋ ์ดํธ ๊ฐ์ฒด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ํน์ ํ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ๊ฐ์ฒด๋ค์ ์ง์ ํ๋ค๊ณ ์ดํดํ๋ฉด ๋ ๋ฏํฉ๋๋ค.
์ด์ ์์ ์์ Printable ํธ๋ ์ดํธ์ ์๋ Age ํ์ ์ ์ฐ๊ด ํ์ ์ด๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ํธ๋ ์ดํธ ๊ตฌํ์ ๊ณตํต์ ์ผ๋ก ํ์ํ ๋ณ์๊ฐ ์๋๋ฐ ์ด๋ค ํ์ ์ด ๋ ์ง๋ ๊ตฌํ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค. print_info ํจ์์์์ ์ฐ๊ด ํ์ ์ ๋์ผํ๊ฒ ๊ตฌํํ ๊ฐ์ฒด๋ค์ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ Person๊ตฌ์กฐ์ฒด์ ์๋ new ํจ์๋ฅผ ์ฐ๊ด ํจ์๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ์์ธํ๋ณด๋ฉด ํจ์์ ์ธ์์ self๊ฐ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ํน์ ๊ตฌ์กฐ์ฒด ๊ฐ์ฒด์ ์ข ์๋์ ๋์ํ๋๊ฒ ์๋๋ผ ๊ฐ์ฒด๊ฐ ์๋ ์ํ์์ Person::new์ ๊ฐ์ด Person์ด๋ผ๋ ํ์ ์ด๋ฆ์ผ๋ก๋ง ํธ์ถํ ์ ์์ต๋๋ค. ๋ณดํต new๋ผ๋ ์ด๋ฆ์ผ๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์ฐ๊ด ํจ์๋ฅผ ๋ง๋๋๊ฒ ๊ด๋ก์ ๋๋ค.
dynํค์๋๋ ํธ๋ ์ดํธ ๊ฐ์ฒด๋ฅผ ๋ํ๋ด๋ ํค์๋์ ๋๋ค. ์ด ํธ๋ ์ดํธ ๊ฐ์ฒด๋ฅผ ์ข๋ ์์ธํ ์ดํดํ ํ์๊ฐ ์์ต๋๋ค.
dyn TraitName
์์์๋ณธ print_infoํจ์๋ฅผ ๋ค์ ๋ณด๊ฒ ์ต๋๋ค. print_infoํจ์๋ item์ด๋ผ๋ ํธ๋ ์ดํธ ๊ฐ์ฒด์ printํจ์๋ฅผ ํธ์ถํฉ๋๋ค. ํ์ ์ด๋ฆ์ด ์๋๋ฐ ์ด๋ป๊ฒ ๊ตฌํํ๋ ํจ์๋ฅผ ํธ์ถํ ์ ์์๊น์?
fn print_info(item: &dyn Printable<Age = u32>) {
item.print();
}
Personํ์ ์ printํจ์๋ 0x1000_0000์ ์๊ณ , Bookํ์ ์ printํจ์๋ 0x3000_0000์ ์๋ค๊ณ ์๊ฐํด๋ด ์๋ค. ์ปดํ์ผ๋ฌ๋ vtable์ด๋ผ๋ ๊ฒ์ ๋ง๋ค์ด์ ํธ๋ ์ดํธ์์ ๊ตฌํ๋ ํจ์๋ค์ ํฌ์ธํฐ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. (์ด๊ฒ์ ์๋ฐ๋ C++์ ์ธํฐํ์ด์ค์ ๋์ผํฉ๋๋ค.)
book.vtable = {
print = 0x1000_0000;
... ๋ค๋ฅธ ํจ์๋ค์ ์์ ์ฃผ์๋ค๋ ๋ค์ด๊ฐ ์ ์์
}
person.vtable = {
print = 0x3000_0000;
... ๋ค๋ฅธ ํจ์๋ค์ ์์ ์ฃผ์๋ค๋ ๋ค์ด๊ฐ ์ ์์
}
fn print_info(item: &dyn Printable<Age = u32>) {
item.vtable.print()
}
์์๊ฐ์ด ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ๊ฐ์ฒด๋ง๋ค vtable์ ์ถ๊ฐํด์ ํธ๋ ์ดํธ ํจ์๋ค์ ํฌ์ธํฐ๋ฅผ ์ ์ฅํฉ๋๋ค. ์ด๋ ๊ฒ ์ถ๊ฐ์ ์ธ ํ ์ด๋ธ์ ๋ง๋ค์ด์ ํจ์ ํฌ์ธํฐ๋ฅผ ์ ์ ํ๊ณ , ์์ฒญ๋ฐ์ ํจ์๋ฅผ ํธ์ถํ๋ ๋ฐฉ์์ Dynamic dispatch๋ผ๊ณ ๋ถ๋ฆ ๋๋ค๋ง ์ฉ์ด๋ณด๋ค๋ ๊ณตํต๋ ํน์ฑ ํน์ ํจ์๋ค์ ๊ตฌํ์ ์ํด ์ถ๊ฐ์ ์ธ ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ๋ค๋ ๊ฒ์ ์๊ณ ์๋๊ฒ ์ค์ํ ๊ฒ์ ๋๋ค. ๋ฌผ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ๋ฒ ๋ ์ฝ๊ฒ๋๋ ๋จ์ ๋ ์์ต๋๋ค๋ง ํน๋ณํ๊ฒ CPU๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ ์ฐ์ฐ์ ์ํํ๋ ๋ถ๋ถ์์ ํธ์ถ๋์ง ์๋ํ ์ฑ๋ฅ์ ์ฐจ์ด๊ฐ ๋์ง ์์ต๋๋ค.
๊ฐ๋ฐ์๋ค์ด ์ง์ ํ์ํ ํธ๋ ์ดํธ๋ฅผ ๋ง๋ค ์ ์์ง๋ง, ๋ฌ์คํธ์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ(The Rust Standard Library: https://doc.rust-lang.org/std/index.html)์์ ๋ฏธ๋ฆฌ ๋ง๋ค๋์ ํธ๋ฆฌํ ํธ๋ ์ดํธ๋ค์ด ์์ต๋๋ค. ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๊ณ ๋ถ๋ฅด๋ ๋งํผ ์ด๋ค ์ํฉ์์๋ ์ฌ์ฉํ ์ ์์๋งํผ ์ฑ๋ฅ์ด๋ ๋ฒ์ฉ์ ์ด ์ข์ ํธ๋ ์ดํธ๋ค์ ๋๋ค. ๊ทธ์ค์์ ์ด๋ณด ๋จ๊ณ์์๋ ์์ฃผ ์ฌ์ฉํ๊ฒ๋๋ ๋ช๊ฐ์ง๋ง ์์ ๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
๊ฐ์ฒด๋ฅผ ํฐ๋ฏธ๋์ ์ถ๋ ฅํ๋ ๋ฐฉ๋ฒ์ ์ด์ผ๊ธฐํด๋ณด๊ฒ ์ต๋๋ค. ํนํ ๋๋ฒ๊น ํ ๋ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ ๊ฒ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์์๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ธํฐ๋ ํฐ๋ธํ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค๋ค๋ณด๋ฉด ๊ฐ์ฒด์ ๊ฐ์ ํฐ๋ฏธ๋์ ์ถ๋ ฅํด์ผ๋ ์ผ์ด ์์ฃผ ์๊น๋๋ค.
๊ฐ์ฒด๋ฅผ ์ถ๋ ฅํ๊ธฐ์ํด์ ์ด๋ฏธ ์ฐ๋ฆฌ๊ฐ ์ฌ๋ฌ๋ฒ ์ฌ์ฉํด๋ณธ๊ฒ ์์ต๋๋ค. ๊ตฌ์กฐ์ฒด์ derive(Debug)๊ตฌ๋ฌธ์ ์ถ๊ฐํด์ ๋๋ฒ๊ทธ ๋ฉ์ธ์ง๋ฅผ ์ถ๋ ฅํ๋๊ฑธ ํด๋ดค์์ต๋๋ค.
#[derive(Debug)]
pub struct Point {
pub x: f64,
pub y: f64,
}
fn main() {
let dot: Point = Point { x: 1.2, y: 3.4 };
println!("{:?}", dot);
}
derive๋ผ๋ ๊ตฌ๋ฌธ์ ์ฌ์ ์ ์ผ๋ก๋ ์ ๋ํ๋ค, ํ์ํ๋ค๋ผ๋ ๋ป์ ๊ฐ์ง๊ณ ์๋๋ฐ Point๋ผ๋ ๊ตฌ์กฐ์ฒด์ ๋ฐ์ดํฐ๋ฅผ ์ถ๋ ฅํ๊ธฐ ์ํ ์ฝ๋๋ฅผ ์๋์ผ๋ก ์์ฑํด๋ฌ๋ผ๋ ์๋ฏธ๊ฐ ๋ฉ๋๋ค. ๋ฌผ๋ก ์๋์ผ๋ก ์์ฑํ์ง์๊ณ ๋ด๊ฐ ์ง์ ๋ง๋ค์ด์ ์ธ ์๋ ์์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ด์ ์ trait์ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด๋ณธ๊ฒ ์ฒ๋ผ ์ง์ ๊ตฌํํด๋ณผ ์ ์์ต๋๋ค. ์ผ๋จ std::fmt::Debug๋ผ๋ trait๊ฐ ์๋ค๋ ๊ฒ์ ์๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ์ ์์ํ ์๋ ์๊ฒ ๋๋ฐ, ์ด ํธ๋ ์ดํธ์ ์ด๋ ๋ฉ์๋๋ฅผ ์ด๋ป๊ฒ ๊ตฌํํด์ผํ๋์ง๋ฅผ ์ด๋์์ ์์๋ณผ ์ ์์๊น์?
impl fmt::Debug for Point {
}
์๋ Debug ํธ๋ ์ดํธ์ ๋ฉ๋ด์ผ์ ํ์ธํ๋ฉด ์ด๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , ์ด๋ค ์ญํ ์ ๊ฐ์ง๋์ง๋ฅผ ์ ์ ์์ต๋๋ค.
https://doc.rust-lang.org/std/fmt/trait.Debug.html
๊ฐ์ฅ ์๋ถ๋ถ์ ๋ณด๋ฉด ํธ๋ ์ดํธ์ ์ ์์ ํ์ ๋ฉ์๋๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
pub trait Debug {
// Required method
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>;
}
โRequired methodโ๋ผ๊ณ ์จ๋์ ๊ฒ์ ๋ณด๋ fmt๋ผ๋ ํจ์๋ฅผ ๊ตฌํํ๋ฉด ๋๊ฒ ๋ค์. ๊ทธ๋ฐ๋ฐ ์ฌ์ค ๊ตฌํ์ ๋ง์ ํ๋ ค๊ณ ํด๋ f๋ผ๋ ์ธ์๋ฅผ ์ด๋ป๊ฒ ์จ์ผํ ์ง ์ ์๋ง ๋ด์๋ ๋ชจ๋ฅผ ์๋ฐ์ ์์ต๋๋ค. ๋งค๋ด์ผ์ ์ข๋ ์ฝ์ด๋ณด๋ฉด ๋ต์ด ๋์ต๋๋ค.
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Point [{} {}]", self.x, self.y)
}
}
์ด๋ฐ ํํ๋ก ์ผ๋ง๋ ์ง ์์ ๋กญ๊ฒ ๊ตฌํ๋งํ๋ฉด ๋ฉ๋๋ค. fmt::Formatter๋ผ๋ ๊ฐ์ฒด์ ๋ด๊ฐ ์ง์ ํ ๋ฉ์ธ์ง๋ฅผ ์จ์ฃผ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ๋จ์ง ์ฃผ์ํ ๊ฒ์ write!๋งคํฌ๋ก ํธ์ถํ๋ ์ฝ๋์์ ์ค์ ๋ง์ง๋ง์ โ;โ ์ธ๋ฏธ์ฝ๋ก ์ ์ฐ์ง ์๋ ๋ค๋ ์ ์ ๋๋ค. fmtํจ์์ ๋ฐํ๊ฐ์ด fmt::Result์ ๋๋ค. write! ๋งคํฌ๋ก ํจ์๊ฐ fmt::Result ๊ฐ์ ๋ฐํํ๋ฏ๋ก โ;โ ์ธ๋ฏธ์ฝ๋ก ์ ์ฐ๋ฉด ์๋ฉ๋๋ค. ๋ง์ฝ ";"๋ฅผ ์ฐ๊ฒ๋๋ฉด ์๋ฌด๋ฐ ๊ฐ๋ ๋ฐํํ์ง ์๊ฒ๋์ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒ์ ๋๋ค.
์ด์ ์ฝ๋๋ฅผ ์คํํด๋ณด๋ฉด ์๋์๊ฐ์ด ์ฐ๋ฆฌ๊ฐ ์ง์ ํ ํํ๋ก ๊ฐ์ฒด์ ๊ฐ์ด ์ถ๋ ฅ๋ฉ๋๋ค.
// src/trait_display_debug/main.rs
use std::fmt;
pub struct Point {
pub x: f64,
pub y: f64,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "POINT({} {})", self.x, self.y)
}
}
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "POINT [{} {}]", self.x, self.y)
}
}
fn main() {
let dot: Point = Point { x: 1.2, y: 3.4 };
println!("{:?}", dot);
println!("For your information: {}", dot);
}
$ cargo run --bin trait_display_debug
Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
Running `target/debug/trait_display_debug`
POINT [1.2 3.4]
For your information: POINT(1.2 3.4)
๊ทธ๋ฐ๋ฐ ๋๋ฒ๊น ์ฉ๋์ธ์๋ ์ฌ์ฉ์์๊ฒ ํน์ ๊ตฌ์กฐ์ฒด์ ๊ฐ๋ค์ ๋ณด์ฌ์ค ํ์๊ฐ ์์๋๊ฐ ์์ต๋๋ค. ๋จ์ํ ๋ด๊ฐ ๋ง๋ ๋ฐ์ดํฐ ๊ฐ์ฒด์ ๊ฐ์ ํ์ธํ๊ธฐ์ํด ๋๋ฒ๊น ์ฉ๋๋ก ์ถ๋ ฅํ ๋๋ ์๊ฒ ์ง๋ง, ๋ด๊ฐ ๋ง๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ๊ฐ์ ธ๋ค์ธ ๋, ๊ฐ์ฒด์ ๊ฐ์ ์ถ๋ ฅํด๋ณผ ์๋ ์๋ ๊ฒ์ ๋๋ค.
ํ์ด์ฌ์ ๊ฒฝํํด๋ณด์ ๋ถ๋ค์ __repr__์ด๋ __str__๋ฉ์๋๊ณผ ์ ์ฌํ ๊ฒ๋ค์ด๋ผ๊ณ ์๊ฐํ์๋ฉด ์ดํดํ๊ธฐ ์ข์ต๋๋ค.
์๋ฅผ ๋ค์ด ๋ด๊ฐ Point๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค์ด์ ์ขํ์์ ์ ์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ํ๋ ๊ธฐ๋ฅ๋ค์ ๊ตฌํํ๋ค๋ฉด, ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฌ์ฉ์๋ ๋ค์๊ณผ ๊ฐ์ด ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ๊ฒ์ ๋๋ค.
fn main() {
let first_dot: Point = get_user();
let second_dot: Point = get_user();
println!("The distance between {} and {} is {}",
first_dot, second_dot, get_distance(first_dot, second_dot));
}
์ฌ์ฉ์๊ฐ ์ถ๋ ฅํ๋ ค๋ ๋ฉ์ธ์ง๋ ๋๋ฒ๊น ๋ฉ์ธ์ง๊ฐ ์๋ ์ ์์ผ๋ก ํฐ๋ฏธ๋์ stdout์ ์ถ๋ ฅํ๋ ค๋ ๋ฉ์ธ์ง์ ๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ๋ฅผ ์ํด์ Debug ํธ๋ ์ดํธ๊ฐ ์๋ std::fmt::Display ํธ๋ ์ดํธ๊ฐ ์กด์ฌํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ฌ์ค ๋ด๋ถ ๊ตฌํ์ Debug ์ ์์ ํ ๋์ผํฉ๋๋ค. ๋จ์ง println!๋ฑ์์ ์ฌ์ฉํ๋ ์ถ๋ ฅ ํํ๊ฐ {:?}๊ฐ ์๋๋ผ {}๋ผ๋ ์ฐจ์ด ๋ฟ์ ๋๋ค.
Debug์ Display๋ ์ฌ์ค์ ๋์ผํ ์ผ์ ํฉ๋๋ค๋ง, ์ฌ์ฉํ๋ ์๋๊ฐ ๋ค๋ฅธ ๊ฒ์ ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ํน์ ํ์ ์ ๋ฌธ์์ด๋ก ๋ณํํด์ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ฃผ๊ณ ์ํ ๋๋ Display๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์๋ก ๋ค๋ฅธ ๋ชจ๋์ด๋ ๊ฐ์ฒด๋ค๊ฐ์ ํต์ ์ธํฐํ์ด์ค๋ก๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ์ง๋ง ๊ฐ๋ฐ์๊ฐ ์์๋ก ๋๋ฒ๊น ์ฉ๋๋ก ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ถ๋ ฅํ๊ณ ์ํ ๋๋ ์๋ฌ ๋ฉ์ธ์ง ๋ฑ์์๋ Debug๋ฅผ ์ฌ์ฉํ๋๊ฒ ์๋์ ๋ง๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์๋์ ๋ง๊ฒ ์ฌ์ฉํ๋ฉด ์ฝ๋๋ฅผ ์ฝ๋ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ ๋ฏธ๋์ ๋ ์์ ์๊ฒ ๋ ์ฝ๊ธฐ ์ฌ์ด ์ฝ๋๊ฐ ๋ ๊ฒ์ ๋๋ค.
Clone ํธ๋ ์ดํธ๋ clone์ด๋ผ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ ๊ฒ์ธ๋ฐ, ๊ฐ๋จํ๊ฒ ์ค๋ช ํ๋ฉด ๋ฐ๋ก deep copy๋ฅผ ์ํํ๋ ๊ฒ์ ๋๋ค. ๋ค์์ Clone ํธ๋ ์ดํธ์ ์ ์๋ฅผ ๋งค๋ด์ผ์์ ๊ฐ์ ธ์จ ๊ฒ์ ๋๋ค.
pub trait Clone: Sized {
// Required method
fn clone(&self) -> Self;
// Provided method
fn clone_from(&mut self, source: &Self) { ... }
}
ํ๊ฐ์ง ๋จผ์ ์์์ผ๋๋๊ฒ ์์ต๋๋ค. self์ Self์ ์ฐจ์ด์ ๋๋ค. self๋ ๊ฐ์ฒด ์์ ์ ๊ฐ๋ฅดํค๋ ๋ณ์์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ Self๋ ๊ฐ์ฒด์ ํ์ ์ ๋๋ค. Self๋ ์๋ฌด๋ฐ ๊ฐ์ฒด์ ์๊ด์์ ๋จ์ง ํ์ฌ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ํ์ ์ ๊ฐ๋ฅดํต๋๋ค. ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ๊ตฌ์กฐ์ฒด์ด๋ฉด ๊ตฌ์กฐ์ฒด์ ์ด๋ฆ์ด๋ผ๊ณ ์๊ฐํ ์ ์์ต๋๋ค.
๊ทธ๋์ cloneํจ์๋ ์๊ธฐ ์์ ์ ์ฐธ์กฐํ๋ฉด์, ๊ฐ์ ํ์ ์ ๋ฐํํ๋ ํจ์์ ๋๋ค. ๊ทธ๋ผ ์์ ๋ฅผ ํ๋ฒ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
// src/trait_clone/main.rs
#[derive(Debug)]
struct Book {
title: String,
author: String,
published: u32,
}
impl Clone for Book {
fn clone(&self) -> Self {
Book {
title: self.title.clone(),
author: self.author.clone(),
published: self.published,
}
}
}
//fn print_info(item: &dyn Clone) {
// println!("item implements Clone trait");
//}
fn main() {
let book = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20230228,
};
let another = Book {
title: String::from("The another book"),
author: String::from("Unknown"),
published: 20111111,
};
let mut book_clone = book.clone();
println!("{:?}", book_clone);
book_clone.clone_from(&another);
println!("{:?}", book_clone);
//print_info(&book);
}
$ cargo run --bin trait_clone
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.25s
Running `target/debug/trait_clone`
Book { title: "The Rust Programming Language", author: "Steve Klabnik and Carol Nichols", published: 20230228 }
Book { title: "The another book", author: "Unknown", published: 20111111 }
cloneํจ์์ ๋ด์ฉ์ ๋ณด๋ฉด ์๋ก์ด Book ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค. titleํ๋๋ self.title์ ๊ทธ๋๋ก ๋ณต์ฌํด์ผํฉ๋๋ค. self.title์ Stringํ์ ์ ๊ฐ์ฒด์ด๋ฏ๋ก Stringํ์ ์ clone๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๋๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. String ํ์ ์ clone ๋ฉ์๋ ๋ํ Clone ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ ๊ฒ์ด๊ฒ ์ง์. ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์๋ ํ์ ๋ค์ ๋๋ถ๋ถ clone ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๋ง์ฝ clone๋ฉ์๋๋ฅผ ํธ์ถํ์ง์๊ณ ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ ๋ค๋ฉด ์ด๋ป๊ฒ๋ ๊น์?
impl Clone for Book {
fn clone(&self) -> Self {
Book {
title: self.title,
author: self.author,
published: self.published,
}
}
}
์์ ๊ถ์ ๋ํด์ ์ค๋ช ํ ๋ ์ด์ผ๊ธฐํ ๋ฐ์ ๊ฐ์ด ํ ์์ญ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋ ๊ฐ์ฒด๋ค์ ์ด์๊ฐ์ด ๋์ ์ด ๋ ๋ ์์ ๊ถ์ ์ด๋์ด ์ผ์ด๋ฉ๋๋ค. ๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
error[E0507]: cannot move out of `self.title` which is behind a shared reference
--> src/main.rs:43:20
|
43 | title: self.title,
| ^^^^^^^^^^ move occurs because `self.title` has type `String`, which does not implement the `Copy` trait
๋ง์ฝ Stringํ์ ์ Copy ํธ๋ ์ดํธ๊ฐ ๊ตฌํ๋์ด์๋ค๋ฉด ์๋์ผ๋ก copy ๋ฉ์๋๋ฅผ ํธ์ถํด์ ์๋์ผ๋ก ๊ฐ์ฒด ๋ณต์ฌ๋ฅผ ํด์ฃผ๊ฒ๋์ง๋ง, String ํ์ ์ Copy ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ์ง์์์ผ๋ฏ๋ก ์์๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ published๋ u32ํ์ ์ ๋ณ์์ด๋ฏ๋ก clone์ด ํ์์์ด ๊ฐ์ด ๋ณต์ฌ๋ฉ๋๋ค.
์ด์ ์์ ์์ ํธ๋ ์ดํธ๋ฅผ ๊ตฌํ ํ ํธ๋ ์ดํธ ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ์ ๋ฌํ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ดค์ต๋๋ค. ๊ทธ๋ผ Clone๋ ํธ๋ ์ดํธ๋๊น ๋น์ทํ๊ฒ Clone์ ๊ตฌํํ ๊ฐ์ฒด๋ค์ ์ธ์๋ก ๋ฐ๋ ํจ์๋ฅผ ๋ง๋ค ์ ์์๊น์? ์์ ์์ ์ฃผ์์ผ๋ก๋ print_info ํจ์๋ฅผ ์ฝ๋๋ก ๋ง๋ค์ด์ ๋ค์ ๋น๋ํด๋ณด๊ฒ ์ต๋๋ค.
...
fn print_info(item: &dyn Clone) {
println!("item implements Clone trait");
}
...
error[E0038]: the trait `Clone` cannot be made into an object
--> src/main.rs:50:22
|
50 | fn print_info(item: &dyn Clone) {
| ^^^^^^^^^ `Clone` cannot be made into an object
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
= note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
์ปดํ์ผ๋ฌ ๋ฉ์ธ์ง๊ฐ ์ฝ๊ฐ ์ดํดํ๊ธฐ ์ด๋ ต์ง๋ง ์ด๋ ๊ฒ ์๊ฐํด๋ณด๋ฉด ํํธ๊ฐ ๋ ์ ์์ต๋๋ค. ํธ๋ ์ดํธ ๊ฐ์ฒด๋ก ์ ๋ฌํ๋ค๋ ๊ฒ์ ์๋์ ํ์ ์ด ๋ญ์ง๋ฅผ ์จ๊ธฐ๊ณ ์ฌ๋ฌ ํ์ ์ด ๊ณตํต์ผ๋ก ๊ตฌํํ ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋๋ค. ๋ง์ฝ ๊ตฌํํ๋ ํจ์๊ฐ clone ๋ฉ์๋์ฒ๋ผ Self๋ฅผ ๋ฐํํ๋ค๋ฉด, ํธ๋ ์ดํธ ๊ฐ์ฒด์ ์๋ ํ์ ์ด ๋ญ์ง ์์์ผ๋ฉ๋๋ค. ๋ฐ๋ผ์ clone ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผํ๋ Clone ํธ๋ ์ดํธ๋ ํธ๋ ์ดํธ ๊ฐ์ฒด๋ก ์ฌ์ฉํ ์ ์๋ ๊ฒ์ ๋๋ค.
์๋ฌ ๋ฉ์ธ์ง์์ ์๋ ค์ฃผ๋ Object safety(https://doc.rust-lang.org/reference/items/traits.html#object-safety) ๋ผ๋ ๊ท์น๋ค์ด ์๋๋ฐ ํธ๋ ์ดํธ ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ค์ด์ ์ธ ์ ์๋ ํธ๋ ์ดํธ๊ฐ ๊ฐ์ ธ์ผํ๋ ๊ท์น๋ค์ ๋๋ค. ์ฌ๊ธฐ์ Sized ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ฉด ์๋๋ค๊ณ ์จ์๋๋ฐ Clone ํธ๋ ์ดํธ๋ ์์ ํธ๋ ์ดํธ๋ก Sized ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ณ ์์ต๋๋ค. ์์ Cloneํธ๋ ์ดํธ์ ์ ์๋ฅผ ๋ณด๋ฉด Clone:Sized๋ผ๊ณ ์จ์๋๋ฐ Sized ํธ๋ ์ดํธ๋ฅผ ์์ ํธ๋ ์ดํธ๋ก ๊ฐ์ง๋ค๋ ํ์์ ๋๋ค. Sized ํธ๋ ์ดํธ๋ ๋ฐ๋ก ํธ๋ ์ดํธ์์ ์ฌ์ฉํ๋ ๋ชจ๋ ํ์ ๋ค์ด ์ปดํ์ผ ์์ ์ ์ด๋ ํฌ๊ธฐ๋ฅผ ๊ฐ๋์ง ์ ์ ์๋ค๋ ํ์์ ๋๋ค ์ปดํ์ผ ํ์์ Self ํ์ ์ ํฌ๊ธฐ๋ฅผ ์์์ผ ๋ฉ๋ชจ๋ฆฌ ๋ณต์ฌ์์ ์์ ์ฑ์ ๋ณด์ฅํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ฐธ๊ณ ๋ก ์ด์๊ฐ์ด ์ด๋ค ๋ฉ์๋๋ฅผ ๊ตฌํํ๊ณ ์ํ๋ ํธ๋ ์ดํธ๊ฐ ์๋๋ผ, ์์ฑ๋ง ๋ถ์ฌํ๊ณ ์ํ๋ ํธ๋ ์ดํธ๋ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ฐ ํธ๋ ์ดํธ๋ค์ Marker trait๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ๊ทธ๋์ Sizedํธ๋ ์ดํธ๊ฐ ์ ์๋ ์์น๊ฐ std::marker์ ๋๋ค.
๋ฌ์คํธ๋ ์ด์๊ฐ์ด ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ์ ์ํด์ ๋ณต์กํด๋ณด์ด๋ ๊ท์น๋ค์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๊ณผํ๋ค์ถ์ ๋๋ ์์ง๋ง, ์ด๋ฐ ๊ท์น๋ค์ ๊ฐ๋ฐ์๊ฐ ์๊ฐํ๋ฉด์ ๊ฐ๋ฐํด์ผํ๋ ์ธ์ด๋ค์ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋๊ฒ ์ดํ ๋ก ์ฝ์ง์์ ์ผ์ด๋ผ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ์ฒ์์๋ ๋ณต์กํด๋ณด์ด๊ณ ์๋ฏธ๋ฅผ ์ ์ ์๋ ๊ท์น๋ค์ด์ง๋ง, ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ์ ์ผ๋ํด๋๊ณ ์ฐ์ต์ ํด๋๊ฐ๋ค๋ฉด ์ดํดํ ์ ์์ต๋๋ค. ์์๋จ๊ณ์์๋ ๋ชจ๋ ํธ๋ ์ดํธ๊ฐ ๋ค ํธ๋ ์ดํธ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์์ง ์๋ค๋ ๊ฒ๋ง ๊ธฐ์ตํด๋๊ณ ์ ์ฐจ ์ต์ํด์ง๋ฉด์ ๋ ์ดํดํ๋ฉด ๋ฉ๋๋ค.
Sized๋ Copy ํธ๋ ์ดํธ ๋ฑ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ธ๋ฐํ๊ฒ ์ ์ดํ ๋ ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ ์ธ ๋ค์ํ ๋ง์ปค ํธ๋ ์ดํธ๊ฐ ์์ง๋ง, ์ด ์ฑ ์ ์์ค์ ๋์ด์๊ธฐ๋๋ฌธ์ ์์ธํ ์ค๋ช ํ์ง ์๊ฒ ์ต๋๋ค.
์ง๊ธ๊น์ง ๊ธธ๊ฒ Clone ํธ๋ ์ดํธ์ ๊ตฌํ์ ์ค๋ช ํ์ง๋ง, ์ฌ์ค์ ์ด๋ ๊ฒ ์ง์ ๊ตฌํํ ํ์๊ฐ ์์ต๋๋ค. derive[Clone]์์ฑ์ ์ถ๊ฐํด์ฃผ๋ฉด ์๋์ผ๋ก Cloneํธ๋ ์ดํธ์ ๊ตฌํ์ด ์์ฑ๋ฉ๋๋ค.
#[derive(Debug, Clone)]
struct Book {
title: String,
author: String,
published: u32,
}
...
Default ํธ๋ ์ดํธ๋ ๊ตฌ์กฐ์ฒด์ ๊ฐ ํ๋๋ฅผ ๋ํดํธ๊ฐ์ผ๋ก ์ด๊ธฐํํด์ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ค๋๋ค. ๋ค์ ์์ ๋ Default ํธ๋ ์ดํธ๋ฅผ ์ง์ ๊ตฌํํ์ง์๊ณ derive(Default) ์์ฑ์ ์ถ๊ฐํด์ ์๋์ผ๋ก ์์ฑ๋ ์ฝ๋๋ฅผ ์ฌ์ฉํ ์์ ์ ๋๋ค.
// src/trait_default/main.rs
#[derive(Debug, Clone, Default)]
struct Book {
title: String,
author: String,
published: u32,
}
fn main() {
let book = Book::default();
let book_clone = book.clone();
println!("{:?}", book_clone);
}
gkim@gkim-laptop:~/study/my-rust-book$ cargo run --bin trait_default
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.13s
Running `target/debug/trait_default`
Book { title: "", author: "", published: 0 }
Defaultํธ๋ ์ดํธ๋ default๋ผ๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. default ๋ฉ์๋๋ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค ๋ ์ฌ์ฉํ๋ฏ๋ก ์ ์ ๋ฉ์๋์ ๋๋ค. ๋ฐ๋ผ์ โํ์ ์ด๋ฆ::default()โ ํํ๋ก ํธ์ถํฉ๋๋ค. ๊ฐํน ์๋์ผ๋ก ์์ฑ๋๋ ๊ฐ๋ค์ด ๊ฐ๋ฐ์์ ์๋์ ๋ค๋ฅผ ๋๋ง ์ง์ ๊ตฌํํด์ฃผ๋ฉด ๋ฉ๋๋ค.
PartialEq๋ ๋ ๊ฐ์ฒด๊ฐ ๊ฐ์ ๊ฐ์ ๊ฐ์ง๊ณ ์๋์ง๋ฅผ ํ์ธํ๋ ํธ๋ ์ดํธ์ ๋๋ค.
// src/trait_partialeq_first/main.rs
#[derive(Debug, Clone, Default)]
struct Book {
title: String,
author: String,
published: u32,
}
impl PartialEq for Book {
fn eq(&self, other: &Self) -> bool {
self.title == other.title && self.author == other.author
}
}
fn main() {
let second = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20230228,
};
let first = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20190812,
};
if second == first {
println!(
"Yes, they are same book but different release {} != {}.",
first.published, second.published
);
}
}
$ cargo run --bin trait_partialeq_first
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/trait_partialeq_first`
Yes, this book is writtend by Person { name: "Steve Klabnik", age: 30 }
์์ ๊ฐ์ด ๋ ์ฑ ์ด ๊ฐ์ ์ฑ ์ธ์ง ํ์ธํ๋ ค๋ฉด ์ฑ ์ ๋ชฉ๊ณผ ์ ์ ์ด๋ฆ์ ํ์ธํ๊ฒ ๋ฉ๋๋ค.
ํธ๋ ์ดํธ ์ด๋ฆ์ด PartialEq๋ผ๊ณ ํด์ ์ Partial์ด๋ผ๋ ์ด๋ฆ์ด ๋ค์ด๊ฐ๋์ง ์์ํ๊ฒ ์๊ฐํ ์๋ ์์ต๋๋ค. ํ์ง๋ง ์์ ํ๊ฒ ๋์ผํ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ๋๊ฒ ์๋๋ผ ์์๊ฐ์ด ์ข๋ ๋์ ์๋ฏธ์์ ์ผ๋ถ ๊ฐ์ ๊ฐ์ ๊ฐ์ง ๊ฐ์ฒด๋ ๋น๊ตํ ์ ์๋ค๋ ์ ์ฐ์ฑ์ ๊ฐ๋๋ค๊ณ ์ดํดํ๋ฉด ์ฌ์ธ๋ฏํฉ๋๋ค. ๋ฐ๋ก ์๋ ์์ ๋ฅผ ์๊ฐํด๋ณด๋ฉด ๋ฉ๋๋ค.
// src/trait_partialeq_second/main.rs
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
#[derive(Debug, Clone, Default)]
struct Book {
title: String,
author: String,
published: u32,
}
impl PartialEq for Book {
fn eq(&self, other: &Self) -> bool {
self.title == other.title && self.author == other.author
}
}
impl PartialEq<Person> for Book {
fn eq(&self, other: &Person) -> bool {
self.author.contains(&other.name)
}
}
impl PartialEq<Book> for Person {
fn eq(&self, other: &Book) -> bool {
other.author.contains(&self.name)
}
}
fn main() {
let second = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20230228,
};
let steve = Person {
name: "Steve Klabnik".to_string(),
age: 30,
};
if second == steve {
println!("Yes, this book is writtend by {:?}", steve);
}
}
$ cargo run --bin trait_partialeq_second
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/trait_partialeq_second`
Yes, this book is writtend by Person { name: "Steve Klabnik", age: 30 }
Book ํ์ ๊ณผ Person ํ์ ์ ๋์ผํ ๊ฐ์ฒด๊ฐ ๋ ์๋ ์์ต๋๋ค. ํ์ง๋ง ์ผ๋ถ ๊ฐ์ ๊ฐ์ ๊ฐ๋์ง๋ฅผ ๋น๊ตํ ์๋ ์๊ฒ ์ง์. ์์ง ์ ๋๋ฆญ์ ๋ํ ์ด์ผ๊ธฐ๋ฅผ ํ์ง ์์์ง๋ง, PartialEq์ ์ด๋ค ํ์ ๋ฐ์ธ๋ฉ์ ์ฐ๋์ง์ ๋ฐ๋ผ์ ๋น๊ตํ ๋์์ ํ์ ์ ์ง์ ํ ์ ์๋ค๋ ๊ฒ๋ง ์๊ฐํด๋ณด์๋ฉด ๋๊ฒ ์ต๋๋ค.
PartialEq ์ธ์๋ Eq ํธ๋ ์ดํธ๊ฐ ์์ต๋๋ค. ํ์ง๋ง ๋ณดํต ์ฐ๋ฆฌ๊ฐ == ์ฐ์ฐ์๋ก ๋น๊ตํ ๋๋ PartialEq๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๊ธฐ์ตํ์๊ธฐ ๋ฐ๋๋๋ค.
๋ฌ์คํธ์์ ์ผ๋ฐ์ ์ผ๋ก ๋ ๊ฐ์ฒด๊ฐ ๊ฐ์์ง ๋น๊ตํ๋ ํธ๋ ์ดํธ๊ฐ PartialEq๋ผ๋ ๊ฒ์ด ์ด์ํ๊ฒ ๋๊ปด์ง ๊ฒ์ ๋๋ค. ์ ์ด๋ฆ์ ์ผ๋ถ๋ถ(Partial)์ด๋ผ๋ ์๋ฏธ๊ฐ ๋ค์ด๊ฐ๋์ง, ์ Eq๊ฐ ๊ธฐ๋ณธ์ด ์๋์ง ์ด์ํฉ๋๋ค. ์ฌ์ค ์ ์๋ง ๋๊ณ ๋ณธ๋ค๋ฉด PartialEq๋ Partial-equivalence ๊ด๊ณ(https://en.wikipedia.org/wiki/Partial_equivalence_relation)๋ฅผ ํ์ธํ๋ ๊ฒ์ ๋๋ค. ์ํ์ ์ธ ํํ๋ค์ ๋จ์ํ์์ผ์ ์๊ฐํด๋ณด๋ฉด
- a=b์ผ๋ b=a๋ฅผ ๋ง์กฑํ๊ณ
- a=b์ด๊ณ b=c์ผ๋ a=c๋ฅผ ๋ง์กฑํ๋์ง๋ฅผ
์ด๋ ๊ฒ 2๊ฐ์ง๋ฅผ ํ์ธํ๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ Eq ํธ๋ ์ดํธ๋ equivalence ๊ด๊ณ(https://en.wikipedia.org/wiki/Equivalence_relation)๋ฅผ ํ์ธํ๋ ๊ฒ์ธ๋ฐ ๋ง์ฐฌ๊ฐ์ง๋ก ์ํ์ ์ธ ํํ๋ค์ ๋จ์ํ์์ผ๋ณด๋ฉด
- a==a๋ฅผ ๋ง์กฑํ๋์ง
ํ์ธํ๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ฐ๋ฐ ๋๋ค ์ํ์ ์ธ ๋ด์ฉ๋ค์ด๋ผ ์ฌ์ค ์๋ฏธ๋ฅผ ์๊ธฐ๊ฐ ์ด๋ ต์ต๋๋ค. ์ฌ์ค ์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ ๋น๊ตํ ๋๋ PartialEq๋ฅผ ์ฐ๋ ๊ฒ์ด ๋ง์ต๋๋ค. ๊ฐ์ ๋น๊ตํ ์ ์๋ ์์ธ์ ์ธ ์ผ์ด์ค๋ค์ด ์๊ธฐ ๋๋ฌธ์ PartialEq๋ผ๋ ์ด๋ฆ์ ์ฌ์ฉํ๋ค๊ณ ํฉ๋๋ค. ๊ทธ๋ฐ ์์ธ์ ์ธ ์ผ์ด์ค๋ค ์ค์ ๋ํ์ ์ผ๋ก ์๊ฐํ๋ ๊ฒ์ด ๋ถ๋์์์ ์ฐ์ฐ์์ ๋ญ๊ฐ ์ฐ์ฐ์ด ์๋ชป๋์์์ ๋ํ๋ด๋ std::f32::NAN์ด๋ผ๋ ๊ฐ์ ๋น๊ตํ ๋ PartialEq๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
assert_eq๋งคํฌ๋ก๋ฅผ ์ด์ฉํด์ std::f32::NAN์ ๋น๊ตํด๋ณด๋ฉด ๋ณด๊ธฐ์๋ ์๋ก ๊ฐ์ผ๋ฏ๋ก ๋ฌธ์ ๊ฐ ์์๊ฒ ๊ฐ์ง๋ง, ์๋ก ๊ฐ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์ผ๋ฏ๋ก ๊ฒฐ๊ตญ ๊ฐ์ง ์๋ค๋ ๊ฒฐ๊ณผ๊ฐ ๋๊ณ , ํจ๋์ ๋ฐ์์ํต๋๋ค.
fn main() {
assert_eq!(std::f32::NAN, std::f32::NAN);
}
์ํ์ ์ผ๋ก ์ซ์ ์๋๊ณผ ์ซ์ ์๋์ ๋น๊ตํ๋ค๋ ๊ฒ์ด ์ ์๋์ง ์์๊ธฐ ๋๋ฌธ์ ๋ ๊ฐ์ด ๊ฐ์ง ์๋ค๊ณ ํ๋จํ๋๋ก ๋ง๋ ๊ฒ์ ๋๋ค. ํ์ด์ฌ๋ฑ ๋๋ถ๋ถ์ ์ธ์ด๋ค๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค.
๊ทธ๋ฐ๋ฐ ์ฌ์ค ์ด๊ฒ ๋ฌด์จ ์๋ฏธ์ธ์ง ์ฝ๊ฒ ์ดํดํ๊ธฐ ์ด๋ ต์ต๋๋ค. ๊ทธ๋์ ์์ ์ฑ ๊ณผ ์ ์๋ฅผ ๋น๊ตํ๋ ์์ ๋ฅผ ์กฐ๊ธ ๋ ํ์ฅํด๋ณด๋ฉด์ ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
//src/trait_partialeq_eq/main.rs
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
#[derive(Debug, Clone, Default)]
struct Book {
title: String,
author: String,
published: u32,
}
impl PartialEq for Book {
fn eq(&self, other: &Self) -> bool {
self.title == other.title && self.author == other.author
}
}
impl PartialEq<Person> for Book {
fn eq(&self, other: &Person) -> bool {
if self.author.contains("Unknown") {
return false;
}
self.author.contains(&other.name)
}
}
impl PartialEq<Book> for Person {
fn eq(&self, other: &Book) -> bool {
if self.name.contains("Unknown") {
return false;
}
other.author.contains(&self.name)
}
}
fn main() {
let second = Book {
title: String::from("Necronomicon"),
author: String::from("Unknown"),
published: 20230228,
};
let unknown = Person {
name: "Unknown".to_string(),
age: 30,
};
if second == unknown {
println!("Yes, this book is writtend by {:?}.", unknown);
} else {
println!("No, we don't know who wrote it.")
}
}
$ cargo run --bin trait_partialeq_eq
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
Running `/home/gkim/study/my-rust-book/target/debug/trait_partialeq_eq`
No, we don't know who wrote it.
์ฑ ์ ์ ์๋ Unknown์ด๊ณ , ์ฌ๋์ ์ด๋ฆ๋ Unknown์ ๋๋ค. ๊ทธ๋ผ ์ด ์ฑ ์ ์์ ์ฌ๋์ ์ด๋ฆ์ด ๊ฐ์ ๊ฒ์ผ๊น์? ์ด ์ฑ ์ ์ด ์ฌ๋์ด ์ผ๋ค๊ณ ์๊ฐํ ์ ์๋ ๊ฒ์ ๋๋ค. ํ๊ธฐ๋ ๊ฐ์ง๋ง ๋น๊ตํ ์ ์๋ ๊ฐ๋ค์ด๊ธฐ ๋๋ฌธ์ ๋๋ค. ์, ์ด๋ฐ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ PartialEq์ด๋ผ๋ ์ด๋ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ผ Eq๊ฐ ํ์ํ ๊ฒฝ์ฐ๋ ์ธ์ ์ผ๊น์? Eq๋ ํญ์ ์ ํํ๊ฒ ๋น๊ตํ ์ ์๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํด์ผํฉ๋๋ค. "Unknown"๊ฐ์ด ๊ฐ๋ค๊ณ ๋น๊ตํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์กด์ฌํ์ง์๊ณ ํญ์ ์ด๋ค ๊ฐ์ด๋ ๋น๊ตํ ์ ์๋ ํ์ ๋ง Eq๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค. ๊ฐ์ฅ ๋ํ์ ์ผ๋ก ํค์ ๊ฐ์ ์ ์ฅํ๋ HashMap๊ฐ์ ์๋ฃ๊ตฌ์กฐ์์ ํค๋ก ์ฌ์ฉํ๋ ํ์ ์ ๋ฐ๋์ Eq ํธ๋ ์ดํธ๊ฐ ๊ตฌํ๋์ด์ผํฉ๋๋ค.
์๋์ ๊ฐ์ด ์ฌ์ฉ์์๊ฒ ํ ๋ฌธ์๋ก๋ ๋ช ๋ น์ ์ ๋ ฅ๋ฐ๋ ํ๋ก๊ทธ๋จ์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
// src/trait_partialeq_assert.main.rs
use std::io;
#[derive(Debug, PartialEq)]
pub enum Command {
Help,
Quit,
Execute(String),
Run,
}
fn user_input() -> Result<Command, String> {
println!("input h/q/r/e: ");
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => match input.as_str().strip_suffix("\n") {
Some("h") => return Ok(Command::Help),
Some("q") => return Ok(Command::Quit),
Some("r") => return Ok(Command::Run),
Some("e") => return Ok(Command::Execute(format!("NOT IMPLEMENTED YET!"))),
_ => return Err(format!("Wrong input: {input}")),
},
Err(error) => return Err(format!("Wrong input: {error}")),
}
}
fn main() {
let com: Command = user_input().expect("Wrong input");
let p = String::new();
assert_ne!(com, Command::Execute(p));
match com {
Command::Help => println!("show help message"),
Command::Quit => return,
Command::Run => println!("do something"),
Command::Execute(path) => println!("execute {path}"),
}
}
$ cargo run --bin trait_partialeq_assert
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.20s
Running `target/debug/trait_partialeq_assert`
input h/q/r/e:
r
do something
ํ๋ก๊ทธ๋จ์ ์คํํ๋ฉด h/q/r ์ค์ ํ๋๋ฅผ ์ ๋ ฅํ๋ผ๋ ๋ฉ์ธ์ง๋ฅผ ์ถ๋ ฅํฉ๋๋ค. ๋ง์ฝ ์ฌ์ฉ์๊ฐ r์ ์ ๋ ฅํ๊ณ ์ํฐ๋ฅผ ์น๋ฉด โdo somethingโ์ด๋ผ๋ ๋ฉ์ธ์ง๋ฅผ ์ถ๋ ฅํฉ๋๋ค. ์ค์ ํ๋ก์ ํธ๋ผ๋ฉด โdo somethingโ์ ์ถ๋ ฅํ๊ฒ ์๋๋ผ ์ค์ ๋ก ๋ญ๊ฐ๋ฅผ ์คํํ๋ ์ฝ๋๊ฐ ์์ ๊ฒ์ ๋๋ค.user_inputํจ์๋ ์ฌ์ฉ์์๊ฒ e๋ผ๋ ๋ช ๋ น์ ์ ๋ ฅ๋ฐ์ผ๋ฉด Command::Execute(์ถ๊ฐ ๋ฉ์ธ์ง)๋ฅผ ๋ฐํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ mainํจ์๋ ๊ฑฐ๊ธฐ์ ๋ง๋ ์ฒ๋ฆฌ๋ฅผ ์คํํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ์์ง ๋ชจ๋ ๊ธฐ๋ฅ์ด ์๋ฃ๋๊ฒ ์๋๋ผ์ mainํจ์์์ assert_ne! ๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํด์ Command::Execute ์ ๋ ฅ์ ๋ฐ์ผ๋ฉด ํ๋ก๊ทธ๋จ์ด ์ค๋จ๋๋๋ก ํ๊ฒ ์ต๋๋ค. ์ถํ์ Command::Execute๋ช ๋ น์ ๋ฐ๋ผ ์คํ๋ ์ฝ๋๋ฅผ ๋จผ์ ๊ตฌํํ ํ์ mainํจ์์์ ์คํ๋๋๋ก ๋ง๋ค ๊ณํ์ ๋๋ค. ๋ณดํต ์์ ์ค์ธ ์ฝ๋๊ฐ ์คํ๋์ง ์๋๋ก ํ ๋ assert๋ assert_eq, assert_ne๋ฑ์ ๋งคํฌ๋ก๋ฅผ ๋ง์ด ์ฌ์ฉํฉ๋๋ค. ๋ค๋ฅธ ์ธ์ด์์๋ ์์ฃผ ์ฌ์ฉํ๋ ๊ธฐ๋ฅ์ ๋๋ค.
์ด๋ฐ assert๊ด๋ จ ๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํ ๋ PartialEq์ ๊ตฌํ์ด ๋ฐ๋์ ํ์ํฉ๋๋ค. ์ ํ์ํ์ง ์ดํดํ๊ธฐ ์ํด ์ผ๋จ Command ํ์ ์ ์๋ derive๋ฅผ ๋นผ๊ณ ๋น๋ํด๋ณด๊ฒ ์ต๋๋ค. ์๋์๊ฐ์ด ์ด์ํ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
...
//#[derive(Debug, PartialEq)]
pub enum Command {
Help,
Quit,
Execute(String),
Run,
}
...
$ cargo run --bin trait_partialeq_assert
Compiling ex v0.1.0 (/Users/user/ex)
error[E0369]: binary operation `==` cannot be applied to type `Command`
--> src/main.rs:29:5
|
29 | assert_ne!(com, Command::Execute(p));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| Command
| Command
|
note: an implementation of `PartialEq` might be missing for `Command`
--> src/main.rs:3:1
|
3 | pub enum Command {
| ^^^^^^^^^^^^^^^^ must implement `PartialEq`
= note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Command` with `#[derive(PartialEq)]`
|
3 + #[derive(PartialEq)]
4 | pub enum Command {
|
error[E0277]: `Command` doesn't implement `Debug`
--> src/main.rs:29:5
|
29 | assert_ne!(com, Command::Execute(p));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Command` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Command`
= note: add `#[derive(Debug)]` to `Command` or manually `impl Debug for Command`
= note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Command` with `#[derive(Debug)]`
|
3 + #[derive(Debug)]
4 | pub enum Command {
|
Some errors have detailed explanations: E0277, E0369.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `ex` (bin "ex") due to 3 previous errors
๊ฐ์ฅ ๋จผ์ ๋ฐ์ํ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ฉด assert_ne! ๋งคํฌ๋ก๊ฐ ์คํ๋ ๋ โ==โ ์ฐ์ฐ์๋ฅผ ์ด์ฉํด์ ๋๊ฐ์ ๊ฐ์ด ๊ฐ์์ง๋ฅผ ํ์ธํ๋๋ฐ, Command ํ์ ์ โ==โ ์ฐ์ฐ์๋ฅผ ์คํํ ์ ์๋ค๋ ๋ง์ ํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์น์ ํ๊ฒ๋ Commandํ์ ์ PartialEq ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋๊ฒ ํ์ํ๋ค๋ ์ค๋ช ์ ํด์ฃผ๋ฉด์ #[derive(PartialEq)]๋ฅผ ํ์ ์ ์ถ๊ฐํ๋ ๊ฒ์ ์ถ์ฒํด์ฃผ๊ณ ์์ต๋๋ค.
๊ทธ ๋ค์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก assert_ne! ๋งคํฌ๋ก๊ฐ Debug ํธ๋ ์ดํธ๋ฅผ ์ฌ์ฉํ๊ณ ์์ผ๋ PartialEq์ ๊ฐ์ด #[derive(Debug)]๋ฅผ ์ถ๊ฐํด์ฃผ๋ผ๋ ์๋ด ๋ฉ์ธ์ง๊ฐ ์ถ๋ ฅ๋์์ต๋๋ค.
์ผ๋จ ์ปดํ์ผ๋ฌ๊ฐ ์๋ ค์ฃผ๋๋๋ก Debug์ PartialEq์ ๊ตฌํ์ ๋ค์ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
...
#[derive(Debug, PartialEq)]
pub enum Command {
Help,
Quit,
Execute(String),
Run,
}
...
Debug์ PartialEq ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด์ฃผ์๋๋ ๋ฌธ์ ์์ด ๋น๋๋๊ณ ์์ต๋๋ค. ์ด์ ๊ฐ์ด ์ผ๋ฐ์ ์ผ๋ก ๋๊ฐ์ ๊ฐ์ ๋น๊ตํ๋ ๊ฒฝ์ฐ์ PartialEq ํธ๋ ์ดํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๊ทธ๋ผ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ์ ๋น๊ตํ ๋ PartialEq๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ์๊ฐํ๋ค๋ฉด ๊ตณ์ด Eq ํธ๋ ์ดํธ๋ฅผ ์ฌ์ฉํด์ผ๋ง ํ๋ ๊ฒฝ์ฐ๋ ๋ฌด์์๊น์? ๋ฐ๋ก ๊ตฌ์กฐ์ฒด๋ฅผ HashMap์ ํค ๊ฐ์ผ๋ก ์ฌ์ฉํ ๋ ์ ๋๋ค.
// src/trait_partialeq_eq_hashmap/main.rs
#[derive(PartialEq, Eq, Hash)]
struct MyKey {
x: i32,
y: i32,
}
struct MyVal {
distance_from_co_origin: f32,
}
fn main() {
let mut map = HashMap::new();
map.insert(
MyKey { x: 3, y: 4 },
MyVal {
distance_from_co_origin: 5.0,
},
);
}
MyKey๋ ์ ์ ์ขํ๋ฅผ ๋ํ๋ ๋๋ค. MyVal์ ์์ ์ผ๋ก๋ถํฐ ์ ์ ๊ฑฐ๋ฆฌ๋ฅผ ๋ํ๋ ๋๋ค. ๊ทธ๋์ ์ฌ๋ฌ ์ ๋ค์ ์์ ์ผ๋ก๋ถํฐ ๊ฑฐ๋ฆฌ๋ฅผ ๊ด๋ฆฌํ๋ ํด์๋งต์ ๋ง๋ค์ด๋ดค์ต๋๋ค. ๋ง์ฝ MyKey ๊ตฌ์กฐ์ฒด์ PartialEq์ Eq ํธ๋ ์ดํธ์ ๊ตฌํ์ด ์๋ค๋ฉด ๋น๋๊ฐ ์๋ฉ๋๋ค. PartialEq๋ Eq์ ์์งํฉ์ด๋ฏ๋ก Eq๊ตฌํ์ ์ํด์๋ PartialEq๊ฐ ํญ์ ๊ฐ์ด ๊ตฌํ๋์ด์ผํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ HashMap์์ ํค ๊ฐ์ผ๋ก ์ฌ์ฉ๋๋ค๋ ํ์๋ฅผ ํ๊ธฐ์ํด Hash ํธ๋ ์ดํธ๋ ๊ตฌํํฉ๋๋ค.
HashMap์ ๋ํด์๋ ๋ค์์ ๋ค์ ์ค๋ช ํ๊ฒ ์ต๋๋ค. ์ด ์์ ์์๋ Eq๋ง ๋ด์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
๋ ๊ฐ์ฒด๊ฐ ๋์ผํ์ง๋ฅผ ํ๋จํ๋ std::cmp::PartialEq ํธ๋ ์ดํธ๋ฅผ ์์๋ดค์ผ๋ ์ด๋ฒ์๋ ํฌ๊ธฐ๋ฅผ ๋น๊ตํ๋ std::cmp::PartialOrd ํธ๋ ์ดํธ์ ๋ํด์ ์์๋ณด๊ฒ ์ต๋๋ค.
๊ทธ๋ผ ๊ฐ๋จํ๊ฒ ๋ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ๋ ์์ ๋ฅผ ๋ณด๊ฒ ์ต๋๋ค.
// src/trait_partialord/main.rs
use std::cmp::Ordering;
#[derive(PartialEq, Eq)]
struct Person {
name: String,
age: i32,
height: i32,
}
impl PartialOrd for Person {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.height <= 0 || other.height <= 0 {
return None;
}
if self.height > other.height {
Some(Ordering::Greater)
} else if self.height < other.height {
Some(Ordering::Less)
} else {
Some(Ordering::Equal)
}
}
}
fn main() {
let alpha = Person {
name: "alpha".to_owned(),
age: 10,
height: 110,
};
let beta = Person {
name: "beta".to_owned(),
age: 10,
height: 100,
};
if alpha > beta {
println!("{} is taller.", alpha.name);
}
if alpha.partial_cmp(&beta).unwrap() == Ordering::Greater {
println!("{} is taller.", alpha.name);
}
}
์ฐ๋ฆฌ๊ฐ ๊ตฌํํด์ผํ ๊ฒ์ PartialOrd ํธ๋ ์ดํธ์ partial_cmp ๋ฉ์๋์ ๋๋ค. ์ด ๋ฉ์๋๋ Option<Ordering>์ ๋ฐํํฉ๋๋ค. ์ Option์ ์ฌ์ฉํ๋์ง๋ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ ์ ์์ต๋๋ค. height ๊ฐ์ด 0์ด๊ฑฐ๋ ์์์ธ ๊ฒฝ์ฐ, ์์ง ๊ฐ์ฒด๊ฐ ์ ๋๋ก ์ด๊ธฐํ๋์ง ์์๊ฑฐ๋ ๋ฒ๊ทธ๋ก ์ธํด ๊ฐ์ฒด์ ๋ฐ์ดํฐ๊ฐ ๊นจ์ก์ ์ ์์ต๋๋ค. ๊ทธ๋ ๊ฒ ๋จ์ํ ๋น๊ต๋ง ํ๋๊ฒ ์๋๋ผ ๋น๊ตํ ์ ์๋ ์ํฉ์ด ์์ ์๋ ์๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฐ ์๋ฌ ์ํฉ์ ์ฒ๋ฆฌํ๊ธฐ์ํด Option์ ๋ฐํํ๋๋ก ํ์ต๋๋ค. Rust์ธ์ด๊ฐ ์ผ๋ง๋ ์๋ฌ ์ฒ๋ฆฌ์ ์ฒ ์ ํ์ง ์ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ PartialOrd ํธ๋ ์ดํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ํ๊ฐ์ง ๋ ์๋กญ๊ฒ ์์์ผํ ๊ฒ์ด ์์ต๋๋ค.
partial_cmp๋ฉ์๋์์ ๊ฐ์ฅ ๋จผ์ ์๋ฌ ์ํฉ์ ํ์ธํ ์ดํ์๋ ์ค์ ๋ก ๋น๊ตํด์ผํ ๋ฐ์ดํฐ๋ฅผ ๋น๊ตํฉ๋๋ค. std::cmp::PartialOrd๋ผ๋ ํธ๋ ์ดํธ์ partial_cmp ๋ฉ์๋์ ๋ฐํ๊ฐ์ด std::cmp::Ordering์ด๋ผ๋ ํ์ ์ ๋๋ค. Ordering์ enum ํ์ ์ผ๋ก Greater, Less, Equal์ด๋ผ๋ 3๊ฐ์ง ํ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๊ฐ์ฒด๊ฐ ๋ ํฌ๋ค๋ฉด Ordering::Greater๋ฅผ ๋ฐํํฉ๋๋ค. ์์ผ๋ฉด Ordering::Less, ๊ฐ์ผ๋ฉด Ordering::Equal์ ๋ฐํํฉ๋๋ค.
mainํจ์์์๋ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ ์ ์๋ 2๊ฐ์ง ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๊ณ ์์ต๋๋ค. ์ฒซ๋ฒ์งธ๋ ์ง๊ด์ ์ผ๋ก โ>โ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. PartialOrd ํธ๋ ์ดํธ๊ฐ ๊ตฌํ๋์๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๊ฐ์ โ>โ์ โ<โ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ๋ฅํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ โ==โ ์ฐ์ฐ์๋ PartialEq ํธ๋ ์ดํธ๊ฐ ๊ตฌํ๋์๊ธฐ ๋๋ฌธ(derive(PartialEq)๋ก ๊ตฌํํ์ต๋๋ค)์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ทธ ๋ค์ ๋ง์ง๋ง์๋ partial_cmp ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถํ๋ ๊ฒ์ ๋ณด์ฌ์ค๋๋ค. '<', '>', '==' ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ๋ํ์ ์ผ๋ก ์ฐ์ฐ์ ๊ฒฐ๊ณผ๊ฐ์ ๋ณ์์ ์ ์ฅํ๊ฑฐ๋, ๋ค๋ฅธ ํจ์์ ์ ๋ฌํด์ผํ ๋ โ<โ๊ฐ์ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๊ฒฝ์ฐ์๋ ์ด๋ ๊ฒ partial_cmp ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถํด์ ๊ฒฐ๊ณผ๊ฐ์ ์ ์ฅํด์ผํฉ๋๋ค.
์ด์ ๋ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ ์ ์๊ฒ ๋์์ต๋๋ค. ๋น๊ตํ๋ฉด ์๊ฐ๋๋๊ฒ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ด์ง์. ํ๋ฐ์ ์๋ ํ์๋ค์ ํค์ ๋ฐ๋ผ ์ ๋ ฌํ๋ ์์ ๋ฅผ ๋ง๋ค์ด๋ณด์์ต๋๋ค.
// src/trait_partialord_sort_first/main.rs
use std::cmp::Ordering;
#[derive(PartialEq, Eq)]
struct Person {
name: String,
age: i32,
height: i32,
}
impl PartialOrd for Person {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.height <= 0 || other.height <= 0 {
return None;
}
if self.height > other.height {
Some(Ordering::Greater)
} else if self.height < other.height {
Some(Ordering::Less)
} else {
Some(Ordering::Equal)
}
}
}
fn class_sorting(people: &mut Vec<Person>) {
let len = people.len();
for i in 0..(len - 1) {
for j in (i + 1)..len {
if people[i] > people[j] {
people.swap(i, j);
}
}
}
}
fn main() {
let mut class: Vec<Person> = vec![
Person {
name: "aaa".to_owned(),
age: 10,
height: 110,
},
Person {
name: "bbb".to_owned(),
age: 10,
height: 100,
},
Person {
name: "ccc".to_owned(),
age: 10,
height: 120,
},
Person {
name: "ddd".to_owned(),
age: 10,
height: 90,
},
];
class_sorting(&mut class);
for p in class.iter() {
println!("{} is {}", p.name, p.height);
}
}
$ cargo run --bin trait_partialord_sort_first
Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.45s
Running `target/debug/trait_partialord_sort_first`
ddd is 90
bbb is 100
aaa is 110
ccc is 120
๊ทธ๋ฆฌ๊ณ ๋๋ถ๋ถ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ทธ๋ ๋ฏ์ด Rust์ ๋ฒกํฐ ํ์ ์๋ ์ ๋ ฌ์ ์ํ ๋ฉ์๋๊ฐ ์์ต๋๋ค. ์ด๋ ๋ฒกํฐ์ ๊ฐ ๋ฐ์ดํฐ๋ค์ ๋น๊ตํ๋ ํด๋ก์ ๋ฅผ ์ ๋ฌํด์ผํ๋ฏ๋ก ์ด๋๋ โ>โ๊ฐ์ ์ฐ์ ์ฐ์ฐ์๊ฐ ์๋๋ผ partial_cmp ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ํด๋ก์ ๋ฅผ ์ฌ์ฉํ๊ฒ๋ฉ๋๋ค.
์๋ ์์ ๋ ๋ฐฑํฐ์ sort_by ๋ฉ์๋์ PartialOrd ํธ๋ ์ดํธ๋ฅผ ์ฌ์ฉํ๋ ์์ ์ ๋๋ค.
// src/trait_partialord_sort_second/main.rs
use std::cmp::Ordering;
#[derive(PartialEq, Eq)]
struct Person {
name: String,
age: i32,
height: i32,
}
impl PartialOrd for Person {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.height <= 0 || other.height <= 0 {
return None;
}
if self.height > other.height {
Some(Ordering::Greater)
} else if self.height < other.height {
Some(Ordering::Less)
} else {
Some(Ordering::Equal)
}
}
}
fn main() {
let mut class: Vec<Person> = vec![
Person {
name: "aaa".to_owned(),
age: 10,
height: 110,
},
Person {
name: "bbb".to_owned(),
age: 10,
height: 100,
},
Person {
name: "ccc".to_owned(),
age: 10,
height: 120,
},
Person {
name: "ddd".to_owned(),
age: 10,
height: 90,
},
];
class.sort_by(|a, b| a.partial_cmp(b).unwrap());
for p in class.iter() {
println!("{} is {}", p.name, p.height);
}
}
$ cargo run --bin trait_partialord_sort_second
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.35s
Running `target/debug/trait_partialord_sort_second`
ddd is 90
bbb is 100
aaa is 110
ccc is 120
๋ฒกํฐ(Vector)๋ ๋ค์์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค. ์ด ์์ ์์๋ partial_cmp ๋ฉ์๋๋ฅผ ์ง์ ํธ์ถํด์ผํ๋ ๊ฒฝ์ฐ์ ๋ํด์๋ง ๋ด์ฃผ์ธ์.
ํน์ ํ์ ์ ๋ค๋ฅธ ํ์ ์ผ๋ก ๋ฐ๊ฟ๋ ์ฌ์ฉํ๋ ํธ๋ ์ดํธ์ ๋๋ค.
์ด ํธ๋ ์ดํธ๊ฐ ์ ์ฒ๋ผ C/C++๋ง ์ฌ์ฉํ์๋ ๋ถ๋ค๊ป๋ ํ์์ฑ์ด ์ ์ดํด๊ฐ ์๋ ์ ์์ต๋๋ค. ์ ๋ ์ฒ์์๋ ์ด๊ฒ ๊ตณ์ด ์ ํ์ํ๊ฐ ์๊ฐํ์์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ํ๋ฒ ์ฌ์ฉํด๋ณด๋ ์ ํ์ํ์ง ์ดํด๊ฐ๋์ ์ ์ ๋ ์์ฃผ ์ฌ์ฉํ๊ฒ๋์์ต๋๋ค. ์ ๊ฐ C/C++๋ก ํ๋ก๊ทธ๋๋ฐํ๋ ๊ฒฝ์ฐ, ํ ๋ชจ๋์์ ๋ค๋ฅธ ๋ชจ๋๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋ ๊ตฌ์กฐ์ฒด์ ๊ฐ ํ๋๋ฅผ ์ชผ๊ฐ์ ์ ๋ฌํ๋๊ฒ ๋ณดํต์ด์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ๋ชจ๋์ ์ฌ๋ฌ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ํ๋์ ์๋ก์ด ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก ๋ง๋ค์ด์ ์ฌ์ฉํ์ต๋๋ค. ์ด ๊ณผ์ ์์ ๋ฐ์ดํฐ ์์๊ฐ ๋ฐ๋๊ฑฐ๋, ํ์ฉ๋์ง ์๋ ๊ฐ์ ์ ๋ฌํ๋ ๋ฑ์ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ์ฝ๊ฒ ํด๊ฒฐํ๊ธฐ ์ด๋ ค์ ์ต๋๋ค.
๊ทธ๋ฐ๋ฐ From/Into๊ฐ์ ํ์ ์ ๋ณํํ๋ ํธ๋ ์ดํธ๊ฐ ์์ผ๋ฉด ๋ชจ๋๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋ ํ์ค ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค ์ ์์ผ๋ฏ๋ก ๋ฐ์ดํฐ ์ ๋ฌ ๊ณผ์ ์์ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ ์ ์๊ฒ๋ฉ๋๋ค.
๋ค์์ Bookํ์ ์ ๊ฐ์ฒด๋ฅผ u32ํ์ ์ ISBN ์ซ์๋ก ๋ฐ๊พธ๋ ์์ ์ ๋๋ค.
// src/trait_from/main.rs
#[derive(Debug)]
struct Book {
title: String,
author: String,
published: u32,
isbn: String,
}
impl From<Book> for u32 {
fn from(book: Book) -> u32 {
book.isbn.parse().unwrap_or(0)
}
}
fn main() {
let the_book = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20230228,
isbn: String::from("718503105"),
};
let rust_in_action = Book {
title: String::from("Rust in Action"),
author: String::from("Tim McNamara"),
published: 20210810,
isbn: String::from("1617294551"),
};
let isbn: u32 = the_book.into();
let isbn2 = u32::from(rust_in_action);
println!("The book is {isbn} and Rust in Action is {isbn2}");
}
$ cargo run --bin trait_from
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.34s
Running `target/debug/trait_from`
The book is 718503105 and Rust in Action is 1617294551
Bookํ์ ์ u32๋ก ๋ณ๊ฒฝํ๊ธฐ ์ํ ๊ฒ์ด๋ฏ๋ก ์ต์ข ์์ฑ๋๋ ๋ฐ์ดํฐ๋ u32ํ์ ์ด ๋ฉ๋๋ค. ๊ทธ๋์ u32ํ์ ์ ์ํด From<Book> ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๋๋ค. from์ด๋ผ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํ๊ฒ๋๋๋ฐ ์ธ์๋ฅผ Book ํ์ ์ ๋ฐ๊ณ , ๋ฐํ๊ฐ์ด u32๊ฐ ๋ฉ๋๋ค.
๋ณดํต From์ ๋ ๋ง์ด ์ฌ์ฉํ๋๋ฐ, From์ ๊ตฌํํ๋ฉด Into๊ฐ ์๋์ผ๋ก ๊ตฌํ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์์ ๋ฅผ ๋ด๋ into ๋ฉ์๋๋ฅผ ๊ตฌํํ์ง ์์๋๋ฐ into ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
From<Book>์์ From์ ํธ๋ ์ดํธ์ ์ด๋ฆ์ด๊ณ , Book์ From ํธ๋ ์ดํธ๊ฐ ๊ตฌํ๋ ํ์ ์ ๋๋ค. ์ด๊ฒ์ ์ ๋๋ฆญ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ๋๋ค. ์ ๋๋ฆญ ํ๋ก๊ทธ๋๋ฐ์ ๋ค์์ ๋ค์ ์ด์ผ๊ธฐํ๊ฒ ์ต๋๋ค. ์ด ์์ ์์๋ From ํธ๋ ์ดํธ๋ฅผ Book ํ์ ์ ์ํด ๊ตฌํํ๋ค๊ณ ์ดํดํด์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
์ข ๋ ๊ฐ๋จํ From/Into๋ฅผ ์์๋ดค์ผ๋, ์ด๋ฒ์๋ ์กฐ๊ธ ๋ ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์๋ TryFrom/TryInto์ ์์ ๋ฅผ ๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฆ์ Try๊ฐ ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด, ์๋๋ฅผ ํด๋ณด๊ณ ์๋๋ฉด ์คํจ๋ฅผ ๋ฐํํ ์ ์๋ ๊ฒ์ด From/Into์ ์ฐจ์ด์ ์ ๋๋ค. ์ด์ ์์ ์์ From/Into์ ๋ฐํ๊ฐ์ ๋ณด๋ฉด Resultํ์ ์ด ์๋๋ผ ๊ณง๋ฐ๋ก u32๋ฅผ ๋ฐํํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์คํจ์ ๋ํ ๊ณ ๋ ค๊ฐ ์์ต๋๋ค.
์ด๋ฒ ์์ ์์๋ TryFrom ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํ๊ณ , try_from ๋ฉ์๋์์ Result๋ฅผ ๋ฐํํ๋๋ก ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
#[derive(Debug)]
struct Book {
title: String,
author: String,
published: u32,
isbn: String,
}
impl TryFrom<Book> for u32 {
type Error = u32;
fn try_from(book: Book) -> Result<u32, Self::Error> {
match book.isbn.parse::<u32>() {
Ok(n) => Ok(n),
Err(_) => Err(0),
}
}
}
fn main() {
let the_book = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20230228,
isbn: String::from("718503105"),
};
let rust_in_action = Book {
title: String::from("Rust in Action"),
author: String::from("Tim McNamara"),
published: 20210810,
isbn: String::from("1617294551"),
};
let isbn: Result<u32, u32> = the_book.try_into();
let isbn2 = u32::try_from(rust_in_action);
println!("The book is {:?} and Rust in Action is {:?}", isbn, isbn2);
}
TryFrom ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด๋ดค์ต๋๋ค. ํธ๋ ์ดํธ ๊ตฌํ์ ๋ณด๋ฉด ๊ฐ์ฅ ์ฒ์ ํ ์ผ์ด Error ํ์ ์ผ๋ก ์ด๋ ํ์ ์ ์ง์ ํ ์ง ๊ฒฐ์ ํ๋ ์ผ์ ๋๋ค. ์ฑ ์ ISBN์ 0์ด ๋ ์ ์์ผ๋ ์๋ฌ ํ์ ์ u32 ํ์ ์ ์๋ก ์ง์ ํ๊ณ ์๋ฌ์ ๊ฒฝ์ฐ Err(0)์ ๋ฐํํ๋๋ก ๋ง๋ค์ด๋ดค์ต๋๋ค. ๋ณด๋ค ์น์ ํ๊ฒ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ์ง์ ํ๊ณ ์ถ์ผ๋ฉด Errorํ์ ์ &โstatic str ํ์ ์ด๋ String ํ์ ์ผ๋ก ์ง์ ํ ์๋ ์๊ฒ ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ try_from ๋ฉ์๋๋ฅผ ๊ตฌํํ๋๋ฐ ๋ฐํ๊ฐ์ด Result<u32, Self::Error>์ ๋๋ค. from๋ฉ์๋์์ u32๋ฅผ ๋ฐํํ๋ ๊ฒ๊ณผ ์ฐจ์ด๊ฐ ์์ต๋๋ค. ๋ฉ์๋์ ๊ตฌํ์ ๊ฐ๋จํฉ๋๋ค. ์ฑ ๋ฐ์ดํฐ์ ์๋ isbn๊ฐ์ด ์ ์์ ์ธ ๊ฐ์ด๋ผ๋ฉด Ok(u32)๊ฐ ๋ฐํ๋ ๊ฒ์ด๊ณ , ์ ์์ ์ธ ๊ฐ์ด ์๋๋ผ์ ํ์ฑ์ค์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด Err(0)์ด ๋ฐํ๋ ๊ฒ์ ๋๋ค.
์ํฉ์ ๋ฐ๋ผ From์ ์ธ ๊ฒ์ธ์ง, TryFrom์ ์ธ ๊ฒ์ธ์ง ์ ํํ๋ฉด๋๊ฒ ์ง๋ง, ๋ณด๋ค ์ ์ฐํ ์๋ฌ์ฒ๋ฆฌ๋ฅผ ์ํด์๋ TryFrom์ ์ฐ๋๊ฒ ์ข์ ๊ฒ์ ๋๋ค.
์ง๊ธ๊น์ง ์ดํฐ๋ ์ดํฐ๋ฅผ ์ฌ๋ฌ๋ฒ ์ฌ์ฉํด๋ดค๋๋ฐ ์ฌ์ค ์ดํฐ๋ ์ดํธ๋ ํธ๋ ์ดํธ๋ก ๊ตฌํ๋ฉ๋๋ค. ๋ฌ์คํธ์ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ํ์ ์๋ ์ดํฐ๋ ์ดํฐ๊ฐ ๋ฏธ๋ฆฌ ๊ตฌํ๋์ด์์ด์ ์ฐ๋ฆฌ๊ฐ ์ง์ ๊ตฌํํ ํ์๊ฐ ์์์ต๋๋ค. ํ์ง๋ง ์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋ ํ์ ์ ์ดํฐ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ฐ๋ฆฌ๊ฐ ์ง์ ๊ตฌํํด์ผ๊ฒ ์ง์.
์ด๋ฒ ์ฅ์์๋ ๋ด๊ฐ ๋ง๋ ๊ตฌ์กฐ์ฒด ํ์ ์ ์ดํฐ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
์๋ ์์ค๋ ์ด์ ์ fmt::Display ํธ๋ ์ดํธ๋ฅผ ๊ตฌํํด๋ณธ ์์ ์ ๋๋ค.
#[derive(Debug)]
struct Book {
title: String,
author: String,
published: u32,
}
fn main() {
let book = Book {
title: String::from("The Rust Programming Language"),
author: String::from("Steve Klabnik and Carol Nichols"),
published: 20230228,
};
println!("{}", book);
}
์ด ์์ ์์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ Book ํ์ ์ ์ดํฐ๋ ์ดํธ๋ฅผ ์ ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
์ฐ์ ์ดํฐ๋ ์ดํฐ๊ฐ ์ด๋ค ํธ๋ ์ดํธ์ธ์ง ๋ฌ์คํธ ๋ฉ๋ด์ผ์ ์ฐพ์๋ณด๊ฒ ์ต๋๋ค.
pub trait Iterator {
type Item;
// Required method
fn next(&mut self) -> Option<Self::Item>;
// Provided methods
....skip...
}
https://doc.rust-lang.org/std/iter/trait.Iterator.html
๋ฉ๋ด์ผ์ ๋ฐ๋ฅด๋ฉด ํ์๋ก ๊ตฌํํด์ผํ next๋ผ๋ ๋ฉ์๋๊ฐ 1๊ฐ์๊ณ , next๋ฉ์๋๋ฅผ ๊ตฌํํ๋ฉด ์๋์ผ๋ก ์ ๊ณต๋๋ ๋ฉ์๋๊ฐ 74๊ฐ์๋ค๊ณ ํฉ๋๋ค. ๊ทธ๋ ๊ฒ ์ด 75๊ฐ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง๋ ํธ๋ ์ดํธ์ ๋๋ค. next๋ฉ์๋๋ ์๊ธฐ ์์ ์ mutable ์ฐธ์กฐ๋ก ๋ฐ์์ Option์ ๊ฐ์ผ ๊ฒฐ๊ณผ ๊ฐ ํ๋๋ฅผ ๋ฐํํ๊ฒ ๋ฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ํด์ผํ ์ผ์ Item์ด๋ผ๋ ํ์ ์ ๋ฌด์์ ์ธ์ง ์ ํด์ผํฉ๋๋ค. ๋ณดํต์ ์์ ์ด ๊ตฌํํ ๊ตฌ์กฐ์ฒด๋ ๊ตฌ์กฐ์ฒด์ ์ฐธ์กฐ๊ฐ ๋๊ฒ ์ง์. ๊ทธ๋ฆฌ๊ณ ์ฃผ์ํด์ผํ ๊ฒ์ด ์ดํฐ๋ ์ดํฐ๊ฐ ํ์ฌ ๋ช๊ฐ์ ๊ฐ์ ๋ฐํํ๋์ง, ๊ทธ๋ฆฌ๊ณ ๋ ์ด์ ๋ฐํํ ๊ฐ์ด ์๋์ง ์๋์ง ๋ฑ์ ์ํ ๊ด๋ฆฌ๋ฅผ ํด์ผ๋๋ค๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ ๊ฒ ์ดํฐ๋ ์ดํฐ๊ฐ ๊ฐ์ง ์ํ๊ฐ ๋ณํ๊ธฐ๋๋ฌธ์ &mut self๋ผ๋ ํ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ผ Book ํ์ ์ ๊ฐ์ฒด๋ค์ ์ฒ๋ฆฌํ๊ธฐ์ํ BookSelf๋ผ๋ ์ดํฐ๋ ์ดํฐ ํ์ ์ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค.
#[derive(Debug)]
struct Book {
title: String,
author: String,
published: u32,
}
#[derive(Debug)]
struct BookShelf<'a> {
books: &'a [Book],
}
impl<'a> Iterator for BookShelf<'a> {
type Item = &'a Book;
fn next(&mut self) -> Option<Self::Item> {
if let Some((first, remains)) = self.books.split_first() {
self.books = remains;
Some(first)
} else {
None
}
}
}
fn main() {
let mut book_array = [
Book {
title: String::from("The Fellowship of the Ring"),
author: String::from("J. R. R. Tolkien"),
published: 19540729,
},
Book {
title: String::from("The Two Towers"),
author: String::from("J. R. R. Tolkien"),
published: 19541111,
},
Book {
title: String::from("The Return of the King"),
author: String::from("J. R. R. Tolkien"),
published: 19551020,
},
];
let mut mybooks_iter = BookShelf {
books: &mut book_array,
};
println!("{:?}", mybooks_iter.next());
println!("{:?}", mybooks_iter.next());
println!("{:?}", mybooks_iter.next());
println!("{:?}", mybooks_iter.next());
let mybooks_for = BookShelf {
books: &mut book_array,
};
for b in mybooks_for {
println!("{:?}", b);
}
}
$ cargo run --bin trait_iterator
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.36s
Running `target/debug/trait_iterator`
Some(Book { title: "The Fellowship of the Ring", author: "J. R. R. Tolkien", published: 19540729 })
Some(Book { title: "The Two Towers", author: "J. R. R. Tolkien", published: 19541111 })
Some(Book { title: "The Return of the King", author: "J. R. R. Tolkien", published: 19551020 })
None
Book { title: "The Fellowship of the Ring", author: "J. R. R. Tolkien", published: 19540729 }
Book { title: "The Two Towers", author: "J. R. R. Tolkien", published: 19541111 }
Book { title: "The Return of the King", author: "J. R. R. Tolkien", published: 19551020 }
์ผ๋จ ๊ตฌํ์ด ์ด๋ป๊ฒํ ์ง๋ ๋๋๊ณ mainํจ์์์ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง๋ถํฐ ๋ณด๊ฒ ์ต๋๋ค.
book_array๋ผ๋ ์ด๋ฆ์ ๋ฐฐ์ด์ ๋ง๋ค์ด์ ์ฌ๋ฌ๊ฐ์ Book ๊ฐ์ฒด๋ฅผ ์ ์ฅํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ mybooks_iter๋ผ๋ ๋ณ์๋ฅผ ๋ง๋๋๋ฐ ์ด ๋ณ์๋ BookSelfํ์ ์ด๊ณ books๋ผ๋ ํ๋์ book_array์ ์ฐธ์กฐ ํฌ์ธํฐ๋ฅผ ์ ์ฅํฉ๋๋ค. mybooks_iter๋ผ๋ ๋ณ์๊ฐ ์ดํฐ๋ ์ดํฐ๊ฐ ๋๋ ๊ฒ์ ๋๋ค. ์ด์ ๋ถํฐ mybooks_iter์ next()๋ผ๋ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค ๋ฐฐ์ด์ ์ ์ฅ๋ Book ํ์ ๊ฐ์ฒด๋ค์ด ํ๋์ฉ ๋ฐํ๋๋ ๊ฒ์ ๋๋ค.
๋ํ ์ดํฐ๋ ์ดํฐ๋ฅผ for ๋ฃจํ์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. mybooks_for๋ผ๋ ์ธํฐ๋ ์ดํฐ๋ฅผ ๋ง๋ค์ด์ for ๋ฃจํ์ ์ฌ์ฉํ๋ฉด next() ๋ฉ์๋๋ฅผ ์๋์ผ๋ก ํธ์ถํด์ค๋๋ค.
๊ทธ๋ผ BookSelf๋ผ๋ ๊ตฌ์กฐ์ฒด๋ ์ด๋ป๊ฒ ๊ตฌํ๋์๋์ง ๋ณผ๊น์. Bookํ์ ๋ฐฐ์ด์ ์ฐธ์กฐ ํฌ์ธํฐ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๊ทธ๋ฅ ๋ฐฐ์ด์ ์์ ์ฃผ์๋ฅผ ๊ฐ์ง๊ณ ์๋๊ฒ ๋ฟ์ ๋๋ค. ์ด๊ฒ์ด ์ด๋ป๊ฒ ์ดํฐ๋ ์ดํฐ ์ญํ ์ ํ ์ ์๋์ง๋ฅผ Iterator ํธ๋ ์ดํธ ๊ตฌํ์ ํ์ธํด์ผ ์ ์ ์์ต๋๋ค.
Iterator ๊ตฌํ์ ๋ณด๋ฉด ๊ฐ์ฅ ๋จผ์ ๋ณผ ์ ์๋๊ฒ Item ํ์ ์ Book๊ฐ์ฒด์ ์ฐธ์กฐ ํฌ์ธํฐ๋ผ๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ ์ดํฐ๋ ์ดํฐ๊ฐ next() ๋ฉ์๋๋ฅผ ํธ์ถํ๊ฑฐ๋ for ๋ฃจํ์์ ์ฌ์ฉ๋ ๋ ๋ฐํํ๋ ๊ฐ์ ํ์ ์ด Book ๊ฐ์ฒด์ ์ฐธ์กฐ ํฌ์ธํฐ๋ผ๋ ๊ฒ์ ๋๋ค. ๊ทธ ๋ค์์ ๋ณด๋ฉด next() ๋ฉ์๋์ ๊ตฌํ์ด ๋์ต๋๋ค. ๋ฉ์๋ ์ธ์๋ &mut self๋ก ์ฐ๋ฆฌ๊ฐ ๋ง๋ BookSelf ๊ตฌ์กฐ์ฒด mutable ์ฐธ์กฐ๊ฐ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฐํ๊ฐ์ธ Option<&Book>์ด ๋๊ฒ ์ง์. ๊ตฌํ์ ์๊ฐ๋ณด๋ค ๊ฐ๋จํฉ๋๋ค. ์ฐ์ ํ์ฌ self.books๋ผ๋ ๋ฐฐ์ด์ ์ฒซ๋ฒ์งธ ๊ฐ์ฒด์ ๋๋จธ์ง๋ก ์ชผ๊ฐญ๋๋ค. ๋ง์ฝ ์ ์ชผ๊ฐ์ง๋ค๋ฉด ์ด์จ๋ ๋ฐฐ์ด์์ ๋ฐ์ดํฐ(Book๊ฐ์ฒด์ ๋ํ ํฌ์ธํฐ)๊ฐ 1๊ฐ ์ด์ ๋ค์ด์๋ค๋ ๋ป์ด๋ฏ๋ก ์ฒซ๋ฒ์งธ ๊ฐ์ฒด๋ ๋ฐํํ๊ณ ๋๋จธ์ง๋ self.books์ ์ ์ฅํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ฐฐ์ด์ ์ชผ๊ฐ๋ ค๊ณ ํ๋๋ฐ None์ด ๋ฐํ๋์๋ค๋ ๊ฒ์ self.books ๋ฐฐ์ด์ ์๋ฌด๋ฐ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ ๋ป์ด๋ฏ๋ก None์ ๋ฐํํด์ฃผ๋ฉด ๋ฉ๋๋ค.
์๋ง ๋ค๋ฅธ ์ธ์ด๋ก ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ง๋ค์ด๋ณธ ๊ฒฝํ์ด ์์ผ์๋ค๋ฉด ์ฝ๊ฒ ์ต์ํด์ง ์ ์์๊ฑฐ๋ผ ์๊ฐํฉ๋๋ค. ๋จ์ง ์ฃผ์ํด์ผํ ๊ฒ์ ๋ฐํ๊ฐ์ Option์ด๋ฏ๋ก ๋์ด์ ๋ฐ์ดํฐ๊ฐ ์์๋ None์ ํธ์ถํด์ผํ๋ค๋ ๊ฒ์ ๋๋ค.
์์ ์ impl<'a>์ Bookshelf<'a>๊ฐ์ด ์๋ก์ด ํํ์ ๋ฌธ๋ฒ์ด ์ฌ์ฉ๋์์ต๋๋ค. ์ด๊ฒ๋ค์ ๋ผ์ดํํ์(Lifetime)์ด๋ผ๊ณ ํฉ๋๋ค. ๋ค์์ ์ ๋๋ก ์๊ฐํ๊ฒ ์ต๋๋ค. ์ผ๋จ ์ด ์์ ์๊ฐ์ด ์์ฃผ ๊ฐ๋จํ๊ฒ ๋ผ์ดํํ์์ ์ฌ์ฉํ ๊ฒฝ์ฐ์๋, ์ผ๋จ ๋ผ์ดํํ์์ ์ง์ ํ์ง์๊ณ ์ฝ๋ฉํ ํ์ ์ปดํ์ผ๋ฌ์ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ์ฐธ๊ณ ํด์ ๋ผ์ดํํ์ ์ง์ ์ ์ถ๊ฐํด์ฃผ๋ฉด ๋ฉ๋๋ค.
์ง๊ธ๊น์ง๋ ๋ฐฐ์ด์ด๋ ๋ฒกํฐ์ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ๋ง ํ๋ ๋ฐ๋ณต์๋ฅผ ์ฌ์ฉํ์์ต๋๋ค. ํ์ง๋ง ๋ณดํต์ ์๋์ ๊ฐ์ด ๋ฐ์ดํฐ๋ฅผ ์์ ํด์ผ๋๋ ์ํฉ์ด ๋ ๋ง์ ๊ฒ์ ๋๋ค.
#[derive(Debug)]
struct Book {
title: String,
author: String,
published: u32,
}
fn main() {
let book_array = [
Book {
title: String::from("The Fellowship of the Ring"),
author: String::from("J. R. R. Tolkien"),
published: 19540729,
},
Book {
title: String::from("The Two Towers"),
author: String::from("J. R. R. Tolkien"),
published: 19541111,
},
Book {
title: String::from("The Return of the King"),
author: String::from("J. R. R. Tolkien"),
published: 19551020,
},
];
for b in book_array.iter() {
b.author = String::from("John Ronald Reuel Tolkien");
}
println!("{:?}", book_array);
}
์ด ์์ ๋ ๋ชจ๋ ์ฑ ์ author ํ๋๋ฅผ "John Ronald Reuel Tolkien"์ผ๋ก ๋ฐ๊พธ๋ ค๋ ์์ ์ ๋๋ค. ์ด ์์ ๋ฅผ ๋น๋ํด๋ณด๋ฉด ์๋์ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
$ cargo build --bin trait_iterator_iter_mut
Compiling pyalgo v0.1.0 (/home/gurugio/pyalgo)
error[E0594]: cannot assign to `b.author`, which is behind a `&` reference
--> src/main.rs:28:9
|
27 | for b in book_array.iter() {
| -----------------
| | |
| | help: use mutable method: `iter_mut()`
| this iterator yields `&` references
28 | b.author = String::from("John Ronald Reuel Tolkien");
| ^^^^^^^^ `b` is a `&` reference, so the data it refers to cannot be written
For more information about this error, try `rustc --explain E0594`.
error: could not compile `pyalgo` (bin "pyalgo") due to 1 previous error
book_array.iter()๋ immutable reference๋ฅผ ๋ฐํํฉ๋๋ค. ๋ฐ๋ผ์ book_array.iter()์์ ๋ฐํ๋ ๋ถ๋ณ ์ฐธ์กฐ๊ฐ b์ ์ ์ฅ๋๊ณ , b๋ฅผ ํตํด ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ์์ ํ ์ ์์ต๋๋ค. ์ปดํ์ผ๋ฌ๊ฐ ์น์ ํ๊ฒ iter() ๋์ ์ iter_mut() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ์๋ ค์ฃผ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ํ๊ฐ์ง ๋ ์์ง ๋ง์์ผํ๋๊ฒ์๋๋ฐ book_array ์ ์ธ์ mut๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค.
#[derive(Debug)]
struct Book {
title: String,
author: String,
published: u32,
}
fn main() {
let mut book_array = [
Book {
title: String::from("The Fellowship of the Ring"),
author: String::from("J. R. R. Tolkien"),
published: 19540729,
},
Book {
title: String::from("The Two Towers"),
author: String::from("J. R. R. Tolkien"),
published: 19541111,
},
Book {
title: String::from("The Return of the King"),
author: String::from("J. R. R. Tolkien"),
published: 19551020,
},
];
for b in book_array.iter_mut() {
b.author = String::from("John Ronald Reuel Tolkien");
}
println!("{:?}", book_array);
}
$ cargo run --bin trait_iterator_iter_mut
Compiling my-rust-book v0.1.0 (/home/gkim/study/my-rust-book)
warning: fields `title` and `published` are never read
--> src/trait_iterator_iter_mut/main.rs:3:5
|
2 | struct Book {
| ---- fields in this struct
3 | title: String,
| ^^^^^
4 | author: String,
5 | published: u32,
| ^^^^^^^^^
|
= note: `Book` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
= note: `#[warn(dead_code)]` on by default
warning: `my-rust-book` (bin "trait_iterator_iter_mut") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s
Running `target/debug/trait_iterator_iter_mut`
[Book { title: "The Fellowship of the Ring", author: "John Ronald Reuel Tolkien", published: 19540729 }, Book { title: "The Two Towers", author: "John Ronald Reuel Tolkien", published: 19541111 }, Book { title: "The Return of the King", author: "John Ronald Reuel Tolkien", published: 19551020 }]
๋ฐฐ์ด์ด๋ ๋ฒกํฐ๋ฅผ ์ฌ์ฉํ ๋ ๋ฐ๋ณต์๋ฅผ ์ง์ ๊ตฌํํ๋ ๊ฒฝ์ฐ๋ ๋ง์ง ์์ ๊ฒ์ ๋๋ค. ๋ณดํต์ ๋คํธ์ํฌ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ฑฐ๋ ๋ณด๋ผ๋, ์คํธ๋ฆผ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ฌ ๋ ๊ฐ์ด ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ํ๊บผ๋ฒ์ ์ฒ๋ฆฌํ์ง์๊ณ ์กฐ๊ธ์ฉ ์ฒ๋ฆฌํ๋ ๊ฒฝ์ฐ์ ๋ฐ๋ณต์๋ฅผ ์ฌ์ฉํฉ๋๋ค.