derive 是 Rust 里最常写的一行属性。这篇不只讲「它能做什么」,而是把它展开:没有它编译器怎么报错、有了它输出什么、它到底生成了哪些 impl 代码、哪些情况下它不能用、对泛型它悄悄加了什么约束。
源码:
1 | struct P { x: i32, y: i32 }
2 | fn main() {
3 | let a = P { x: 1, y: 2 };
4 | println!("{:?}", a);
5 | let b = a.clone();
6 | println!("{}", a == b);
7 | }
编译:失败
error[E0277]: `P` doesn't implement `Debug`
--> <实验目录>/src/u11a.rs:4:22
|
4 | println!("{:?}", a);
| ---- ^ `P` cannot be formatted using `{:?}` because it doesn't implement `Debug`
| |
| required by this formatting parameter
|
= help: the trait `Debug` is not implemented for `P`
help: consider annotating `P` with `#[derive(Debug)]`
|
1 + #[derive(Debug)]
2 | struct P { x: i32, y: i32 }
|
error[E0599]: no method named `clone` found for struct `P` in the current scope
--> <实验目录>/src/u11a.rs:5:15
|
1 | struct P { x: i32, y: i32 }
| -------- method `clone` not found for this struct
...
5 | let b = a.clone();
| ^^^^^ method not found in `P`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `Clone`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`. 源码:
1 | #[derive(Debug, Clone, PartialEq, Default)]
2 | struct P { x: i32, y: i32, name: String }
3 | fn main() {
4 | let a = P { x: 1, y: 2, name: "a".into() };
5 | let b = a.clone();
6 | println!("{:?}", a);
7 | println!("{:#?}", b);
8 | println!("a == b : {}", a == b);
9 | println!("Default:{:?}", P::default());
10 | }
编译:成功
运行(退出码 0):
P { x: 1, y: 2, name: "a" }
P {
x: 1,
y: 2,
name: "a",
}
a == b : true
Default:P { x: 0, y: 0, name: "" } #[prelude_import]
struct P {
x: i32,
y: i32,
}
#[automatically_derived]
impl ::core::fmt::Debug for P {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "P", "x",
&self.x, "y", &&self.y)
}
}
#[automatically_derived]
impl ::core::clone::Clone for P {
#[inline]
fn clone(&self) -> P {
P {
x: ::core::clone::Clone::clone(&self.x),
y: ::core::clone::Clone::clone(&self.y),
}
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for P { }
#[automatically_derived]
impl ::core::cmp::PartialEq for P {
#[inline]
fn eq(&self, other: &P) -> bool { self.x == other.x && self.y == other.y }
}
fn main() {}展开用的是 RUSTC_BOOTSTRAP=1 rustc -Z unpretty=expanded:在稳定版编译器上打开了只有 nightly 才有的 -Z 选项,仅用于观察。过程宏的执行阶段见过程宏的执行阶段,derive 宏的实现见Derive 宏如何生成代码。
源码:
1 | #[derive(Clone, Copy)]
2 | struct S { name: String }
3 | fn main() {}
编译:失败
error[E0204]: the trait `Copy` cannot be implemented for this type
--> <实验目录>/src/u11d.rs:2:8
|
1 | #[derive(Clone, Copy)]
| ---- in this derive macro expansion
2 | struct S { name: String }
| ^ ------------ this field does not implement `Copy`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0204`.
源码:
1 | #[derive(Debug, PartialEq, PartialOrd)]
2 | struct Ver { major: u32, minor: u32 }
3 | #[derive(Debug, PartialEq, PartialOrd)]
4 | enum Level { Low, Mid, High }
5 | fn main() {
6 | println!("{}", Ver { major: 1, minor: 9 } < Ver { major: 2, minor: 0 });
7 | println!("{}", Ver { major: 2, minor: 1 } < Ver { major: 2, minor: 0 });
8 | println!("{}", Level::Low < Level::High);
9 | println!("{:?}", Level::Mid.partial_cmp(&Level::Low));
10 | }
编译:成功
运行(退出码 0):
true
false
true
Some(Greater) 源码:
1 | #[derive(Debug, Clone)]
2 | struct W<T> { v: T }
3 | struct NoClone;
4 | fn main() {
5 | let a = W { v: 5 }; let b = a.clone(); println!("{:?}", b);
6 | let c = W { v: NoClone };
7 | let d = c.clone();
8 | }
编译:失败
error[E0599]: the method `clone` exists for struct `W<NoClone>`, but its trait bounds were not satisfied
--> <实验目录>/src/u11f.rs:7:15
|
2 | struct W<T> { v: T }
| ----------- method `clone` not found for this struct because it doesn't satisfy `W<NoClone>: Clone`
3 | struct NoClone;
| -------------- doesn't satisfy `NoClone: Clone`
...
7 | let d = c.clone();
| ^^^^^ method cannot be called on `W<NoClone>` due to unsatisfied trait bounds
|
note: trait bound `NoClone: Clone` was not satisfied
--> <实验目录>/src/u11f.rs:2:10
|
1 | #[derive(Debug, Clone)]
| ----- in this derive macro expansion
2 | struct W<T> { v: T }
| ^ type parameter would need to implement `Clone`
= help: consider manually implementing the trait to avoid undesired bounds
help: consider annotating `NoClone` with `#[derive(Clone)]`
|
3 + #[derive(Clone)]
4 | struct NoClone;
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.