You can implement the Copy
trait to give the type copy-semantics instead of move-semantics. This can only be done if all its constituent elements (each factor of a product type, or each factor of each variant of a sum-type) are also Copy
.
This allows you to also make rather large types Copy
. Can implementing Copy
be detrimental to performance if the size of the type is "large"?
If Copy
should always be implemented, why is it not an auto-trait like Sync
and Send
for those types which can implement it and have opt-out semantics instead of opt-in?
Option<&mut T> can't implement Clone or Copy because &mut T doesn't, for lifetime reasons. If the compiler supported some special trait, say BorrowCopyOfPointer , then Option<&mut T> could implement that, as could other wrapper types ( &mut T would implicitly implement it).
For this reason, String is Clone but not Copy . Clone is a supertrait of Copy , so everything which is Copy must also implement Clone . If a type is Copy then its Clone implementation only needs to return *self (see the example above).
Yes, this is correct. In Rust terms, &T is Copy , which means that it can be copied bitwise without transferring ownership.
why is [
Copy
] not an auto-trait likeSync
andSend
for those types which can implement it and have opt-out semantics instead of opt-in?
Copy
used to be automatically implemented by types that could implement it. This behavior was changed in December 2014, not too long before Rust 1.0.
Should the
Copy
trait always be implemented if possible?
Not necessarily. When developing a library, the choice to implement Copy
or not on a type has an impact on forward compatibility. Removing a Copy
implementation on a type is a breaking change (users of that type may rely on the type being copied instead of moved), and as such would impose a major version bump on the library in order to respect semantic versioning. In particular, if a type is able to implement Copy
now but you think it's possible that the type may evolve such that it could no longer implement Copy
, you should play it safe and not implement Copy
on that type.
Another reason for not implementing Copy
is, as you mentioned, large types. It may be useful to implement only Clone
for such types, as usually "Clone
but not Copy
" indicates that cloning the value is not "cheap". However, even if a type is not Copy
, one could still cause a large memory copy operation by merely moving the value (though if you're lucky, the compiler might optimize it away).
Can implementing
Copy
be detrimental to performance if the size of the type is "large"?
Not if you never perform a copy on the type! Keep in mind that the only difference between a move and a copy is that a move makes the source unusable (i.e. the compiler will raise an error if you try to use a value after it was moved), while a copy doesn't; both operations are implemented as a shallow memory copy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With