Usar a característica derive
Talvez você tenha notado que nossos tipos personalizados são um pouco difíceis de usar na prática. Esse struct Point
simples não pode ser comparado com outras instâncias de Point
nem exibido no terminal. Devido a essa dificuldade, podemos usar o atributo derive para permitir que novos itens sejam gerados automaticamente para o struct.
Desvantagem dos tipos genéricos
Dê uma olhada no seguinte exemplo de código:
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 4, y: -3 };
if p1 == p2 { // can't compare two Point values!
println!("equal!");
} else {
println!("not equal!");
}
println!("{}", p1); // can't print using the '{}' format specifier!
println!("{:?}", p1); // can't print using the '{:?}' format specifier!
}
O código anterior falhará por três motivos. Veja esta saída:
error[E0277]: `Point` doesn't implement `std::fmt::Display`
--> src/main.rs:10:20
|
10 | println!("{}", p1);
| ^^ `Point` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `Point`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required by `std::fmt::Display::fmt`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: `Point` doesn't implement `Debug`
--> src/main.rs:11:22
|
11 | println!("{:?}", p1);
| ^^ `Point` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Point`
= note: add `#[derive(Debug)]` or manually implement `Debug`
= note: required by `std::fmt::Debug::fmt`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0369]: binary operation `==` cannot be applied to type `Point`
--> src/main.rs:13:11
|
13 | if p1 == p2 {
| -- ^^ -- Point
| |
| Point
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `Point`
error: aborting due to 3 previous errors#+end_example
Esse código não é compilado porque nosso tipo Point
não implementa as seguintes características:
- A característica
Debug
, que permite que um tipo seja formatado usando o especificador de formato{:?}
, é usada em um contexto de depuração voltado para o programador. - A característica
Display
, que permite que um tipo seja formatado usando o especificador de formato{}
, é semelhante aDebug
. No entanto,Display
é mais adequado à saída voltada para o usuário. - A característica
PartialEq
, que permite que os implementadores sejam comparados por igualdade.
Usar derive
Felizmente, as características Debug
e PartialEq
poderão ser implementadas automaticamente para nós pelo compilador Rust usando o atributo #[derive(Trait)]
, se cada um de seus campos implementar a característica:
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
Nosso código ainda não será compilado porque a biblioteca padrão do Rust não fornece implementação automática para a característica Display
, pois ela é destinada aos usuários finais. No entanto, se comentarmos essa linha, nosso código agora produzirá essa saída:
not equal!
Point { x: 1, y: 2 }
Ainda assim, podemos implementar a característica Display
para nosso tipo por conta própria:
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
O código agora será compilado:
not equal!
(1, 2)
Point { x: 1, y: 2 }
Confira o código deste exemplo neste link do Rust Playground.