5. 알아 두면 도움 되는 standard trait (1/2)
1. Debug
Debug 트레이트는 Rust 컴파일러에게 데이터를 출력하기 위해 어떤 포맷을 적용할지 알려 줍니다,
앞에서도 여러 번 봤지만, {:?}나 {:#?} 같은 포맷터를 사용할 수 있게 됩니다.
2. Clone
Clone 트레이트는 데이터 값을 명시적으로 복사할 수 있게 만듭니다.
이 트레이트를 적용함으로써 clone 메서드를 사용할 수 있게 됩니다.
fn main() {
let point1 = Point {
x: 1,
y: 1,
};
let point2 = point 1.clone(); // 1
}
#[derive(Clone)]
struct Point {
x: i32,
y: i32,
}
// 1: Clone 트레이트가 적용된 타입의 인스턴스에는 그 전에는 안 보이던 clone 메서드가 추가되어 사용할 수 있습니다.
3. Copy
이 트레이트가 적용되면 데이터 값의 복사본을 자동으로 만들어 줍니다.
앞에서도 여러 번 봤지만, 참조로 빌려온 값이나 heap 메모리에 존재하는 데이터는 Copy 트레이트가 적용되어 있지 않았습니다.
이 트레이트를 사용할 때 주의할 점이 있습니다.
Copy 트레이트는 반드시 Clone 트레이트와 함께 사용해야 합니다.
Clone 트레이트는 복사를 가능하게 하고, Copy 트레이트는 복사가 자동으로 이루어지도록 만든다고 기억하면 쉽습니다.
#[derive(Clone, Copy)] // 3
struct Point {
x: i32,
y: i32,
}
fn main() {
let point1 = Point {
x: 1,
y: 1,
};
let point2 = point1.clone();
let point3 = point1; // 1
let point4 = point1; // 2
}
// 3: Copy 트레이트를 Clone 트레이트와 함께 구현했습니다.
// 1: point1을 새로운 변수 point3에 할당했습니다. 이때 자동으로 데이터의 복사가 일어납니다. 이때 소유권 이동이 일어나지 않고 복사가 일어났다는 것을 확인하기 위해 // 2에서 한 번 더 할당을 했지만 에러가 발생하지 않았습니다.
4. PartialEq
이 트레이트는 두 데이터가 같은지 비교하는 것을 가능하게 합니다.
그래서 이 트레이트가 구현된 데이터 타입은 “==“을 사용해서 비교를 할 수 있습니다.
#[derive(Clone, Copy)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point1 = Point {
x: 1,
y: 1,
};
let point2 = point1.clone();
let point3 = point1;
let point4 = point1;
let mut is_equal = point3 == point4; // 1
println!("{}", is_equal);
}
// 출력
...에러
| let mut is_equal = point3 == point4;
| ------ ^^ ------ Point
| |
| Point
|
note: an implementation of `PartialEq<_>` might be missing for `Point`
--> src/main.rs:16:1
|
16 | struct Point {
| ^^^^^^^^^^^^ must implement `PartialEq<_>`
help: consider annotating `Point` with `#[derive(PartialEq)]`
|
16 | #[derive(PartialEq)]
// 1: point1의 복사본인 point3와 point4가 같은지 “==“을 사용해서 비교했습니다. 하지만 에러가 발생합니다.
// 출력: 에러 메시지를 보면 #[derive(PartialEq)]를 attribute으로 적용하라고 권하고 있습니다.
PartialEq 트레이트를 적용하고 다시 출력해 보겠습니다.
fn main() {
let point1 = Point {
x: 1,
y: 1,
};
let point2 = point1.clone();
let point3 = point1;
let point4 = point1;
let mut is_equal = point3 == point4;
println!("{}", is_equal);
}
#[derive(Clone, Copy, PartialEq)]
struct Point {
x: i32,
y: i32,
}
// 출력
true
// 출력: 기대한 대로 true가 출력되었습니다.
PartialEq 트레이트를 적용할 때 한 가지 주의할 점이 있습니다.
PartialEq 트레이트가 적용된 데이터 타입이라도 같은 데이터 타입끼리만 비교할 수 있습니다.
다음 코드를 보면서 자세히 알아보겠습니다.
fn main() {
let point1 = Point {
x: 1,
y: 1,
};
let plain1 = Plain2d{
x:1,
y:1
};
let is_equal = point1 == plain1; // 3
println!("{}", is_equal);
}
#[derive(PartialEq)] // 1
struct Point {
x: i32,
y: i32,
}
#[derive(PartialEq)] // 2
struct Plain2d{
x:i32,
y:i32
}
// 출력
...에러
12 | let is_equal = point1 == plain1;
| ^^^^^^ expected struct `Point`, found struct `Plain2d`
//1 : Point 구조체에 PartialEq가 적용되었습니다.
// 2: Plain2d 구조체에 PartialEq가 적용되었습니다.
// 3: Point 타입 변수와 Plain2d 타입 변수를 비교했지만 에러가 발생합니다.
// 출력: 에러 메시지를 보면 Point 타입끼리 비교해야 되는데, 기대하지 않았던 Plain2d 타입이 비교되고 있다고 알려 줍니다.
만약 타입이 다른 데이터를 서로 비교하고 싶다면 PartialEq 트레이트를 수동으로 구현해야 합니다.
다음 코드에서 구현해 보겠습니다.
#[derive(PartialEq)] // 1
struct Point {
x: i32,
y: i32,
}
struct Plain2d{ // 2
x:i32,
y:i32
}
// 3
impl PartialEq<Point> for Plain2d{
fn eq(&self, other: &Point) -> bool {
(self.x == other.x) && (self.y == other.y)
}
}
fn main() {
let point1 = Point {
x: 1,
y: 1
};
let plain1 = Plain2d{
x:1,
y:1
};
let is_equal = plain1.eq(&point1); // 4
println!("{}", is_equal);
let is_eq = plain1 == point1; // 5
println!("{}", is_eq);
}
// 출력
true
// 3: 트레이트를 구현하는 문법대로 PartialEq 트레이트를 Plain2d 타입에 구현했습니다.
여기서 PartialEq<Point>의 <Point> 부분은 Point 타입과 비교할 것임을 알려 주고 있습니다.
이 부분 때문에 서로 다른 타입과도 비교가 가능합니다.
구현부를 보면, PartialEq 트레이트는 eq 함수를 구현하도록 강제하고 있기 때문에 eq 함수를 구현했습니다.
eq 함수 구현부를 보면 Plain2d 타입은 self로, Point 타입은 other 파라미터로 받아 옵니다.
그리고 구조체 안의 필드 각각을 비교하고 결과를 반환합니다.
// 4: eq 메서드를 사용해서 비교를 하고 있습니다.
eq 함수 대신 “==“도 사용할 수 있습니다 다만 좌우를 바꾸어서 point1 == plain1로 하면 에러가 납니다.
왜냐 하면 Point에 구현된 PartialEq 트레이트는 수동으로 따로 구현하지 않았기 때문에 같은 타입만 비교하도록 되어 있기 때문입니다.
// 1: attribute으로 PartialEq을 구현했습니다.
// 2: PartialEq을 구현한 attribute이 없습니다.
수동으로 트레이트를 구현하고 동시에 같은 트레이트의 attribute도 구현하면 에러가 발생합니다.
'Rust 입문' 카테고리의 다른 글
[Rust] crate.io (0) | 2022.10.13 |
---|---|
[Rust] 알아 두면 도움되는 standard trait (2/2) (0) | 2022.10.13 |
[Rust] Standard trait와 derivable trait (0) | 2022.10.13 |
[Rust] Dynamic Object (0) | 2022.10.13 |
[Rust] 트레이트 바운드 (Trait Bound) (0) | 2022.10.13 |