Estimated time: 1 day
Rust has a standard way to deal with default values of a type via Default
trait. Read through its official docs to understand the design.
It can be auto-derived, but only for a struct
whose all members have Default
implementations. It is implemented for a great many types in the standard library, and also used in a surprising number of places. So if your type has a value that can be construed as being "default", it is a good idea to implement this trait.
If you're not enough with std deriving capabilities for Default
, consider to use smart-default crate. An example is quite self-explanatory:
#[derive(SmartDefault)]
enum Foo {
Bar,
#[default]
Baz {
#[default = 12]
a: i32,
b: i32,
#[default(Some(Default::default()))]
c: Option<i32>,
#[default(_code = "vec![1, 2, 3]")]
d: Vec<u32>,
#[default = "four"]
e: String,
},
Qux(i32),
}
A great thing that having a Default
implementation you can instantiate your struct
with only the non-default values and have all other fields filled with default values:
let x = Foo { bar: baz, ..Default::default() };
By default, all types in Rust follow 'move semantics'.
If you need a duplicate of a value, then its type should implement Clone
trait (see official docs), and a duplicate is created by calling Clone
methods explicitly. Cloning can be either cheap or expensive operation depending on type semantics.
However, Copy
marker trait (see official docs) enables 'copy semantics' for a type, so a value is copied implicitly every time is passed. That's why copying must always perform a simple bit-to-bit copy operation.
Official Copy
docs are quite explanatory about which types should be Copy
and which types cannot:
Some types can't be copied safely. For example, copying
&mut T
would create an aliased mutable reference. CopyingString
would duplicate responsibility for managing theString
's buffer, leading to a double free.Generalizing the latter case, any type implementing
Drop
can't beCopy
, because it's managing some resource besides its ownsize_of::<T>
bytes.
Generally speaking, if your type can implement
Copy
, it should. Keep in mind, though, that implementingCopy
is part of the public API of your type. If the type might become non-Copy
in the future, it could be prudent to omit theCopy
implementation now, to avoid a breaking API change.
For better understanding the topic, read through:
- Create a
Point
type which represents a 2D point (x
andy
coordinates). This type has to beCopy
andDefault
. - Create a
Polyline
type which represents a non-empty set ofPoint
s of unknown size. This type has to beClone
and non-Default
.
After completing everything above, you should be able to answer (and understand why) the following questions: