Skip to content

Commit 967c388

Browse files
Rollup merge of rust-lang#33815 - carols10cents:trait-documentation-clarifications, r=steveklabnik
Trait documentation clarifications Hi! I've felt a bit of friction lately in figuring out how to write custom implementations of the `derive`able traits, so I decided to add to the docs :) The docs for `Copy` are already excellent-- clear, useful sections that I only reordered a bit-- they're now: * General explanation * When can my type be `Copy`? * When can my type _not_ be `Copy`? * When should my type be `Copy`? * Derivable * How can I implement `Copy`? I didn't add all these sections for all the traits, but I did make sure all the derivable traits had a consistent "Derivable" section that explained what the derived implementation does and a "How can I implement" section that has an example. Please check me for correctness-- I tried to do research to make sure I was saying accurate things but I'm still learning! ❤️ I'd also love suggestions on information to add that is still missing-- I think these traits are important and deserve to have awesome docs!
2 parents 5751495 + 1e809f5 commit 967c388

File tree

6 files changed

+313
-100
lines changed

6 files changed

+313
-100
lines changed

src/libcore/clone.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,42 @@
4646

4747
use marker::Sized;
4848

49-
/// A common trait for cloning an object.
49+
/// A common trait for the ability to explicitly duplicate an object.
5050
///
51-
/// This trait can be used with `#[derive]`.
51+
/// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while
52+
/// `Clone` is always explicit and may or may not be expensive. In order to enforce
53+
/// these characteristics, Rust does not allow you to reimplement `Copy`, but you
54+
/// may reimplement `Clone` and run arbitrary code.
55+
///
56+
/// Since `Clone` is more general than `Copy`, you can automatically make anything
57+
/// `Copy` be `Clone` as well.
58+
///
59+
/// ## Derivable
60+
///
61+
/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d
62+
/// implementation of `clone()` calls `clone()` on each field.
63+
///
64+
/// ## How can I implement `Clone`?
5265
///
5366
/// Types that are `Copy` should have a trivial implementation of `Clone`. More formally:
5467
/// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`.
5568
/// Manual implementations should be careful to uphold this invariant; however, unsafe code
5669
/// must not rely on it to ensure memory safety.
70+
///
71+
/// An example is an array holding more than 32 elements of a type that is `Clone`; the standard
72+
/// library only implements `Clone` up until arrays of size 32. In this case, the implementation of
73+
/// `Clone` cannot be `derive`d, but can be implemented as:
74+
///
75+
/// ```
76+
/// #[derive(Copy)]
77+
/// struct Stats {
78+
/// frequencies: [i32; 100],
79+
/// }
80+
///
81+
/// impl Clone for Stats {
82+
/// fn clone(&self) -> Stats { *self }
83+
/// }
84+
/// ```
5785
#[stable(feature = "rust1", since = "1.0.0")]
5886
pub trait Clone : Sized {
5987
/// Returns a copy of the value.

src/libcore/cmp.rs

Lines changed: 164 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,43 @@ use option::Option::{self, Some};
5353
/// symmetrically and transitively: if `T: PartialEq<U>` and `U: PartialEq<V>`
5454
/// then `U: PartialEq<T>` and `T: PartialEq<V>`.
5555
///
56+
/// ## Derivable
57+
///
58+
/// This trait can be used with `#[derive]`. When `derive`d on structs, two
59+
/// instances are equal if all fields are equal, and not equal if any fields
60+
/// are not equal. When `derive`d on enums, each variant is equal to itself
61+
/// and not equal to the other variants.
62+
///
63+
/// ## How can I implement `PartialEq`?
64+
///
5665
/// PartialEq only requires the `eq` method to be implemented; `ne` is defined
5766
/// in terms of it by default. Any manual implementation of `ne` *must* respect
5867
/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and
5968
/// only if `a != b`.
6069
///
61-
/// This trait can be used with `#[derive]`.
70+
/// An example implementation for a domain in which two books are considered
71+
/// the same book if their ISBN matches, even if the formats differ:
72+
///
73+
/// ```
74+
/// enum BookFormat { Paperback, Hardback, Ebook }
75+
/// struct Book {
76+
/// isbn: i32,
77+
/// format: BookFormat,
78+
/// }
79+
///
80+
/// impl PartialEq for Book {
81+
/// fn eq(&self, other: &Book) -> bool {
82+
/// self.isbn == other.isbn
83+
/// }
84+
/// }
85+
///
86+
/// let b1 = Book { isbn: 3, format: BookFormat::Paperback };
87+
/// let b2 = Book { isbn: 3, format: BookFormat::Ebook };
88+
/// let b3 = Book { isbn: 10, format: BookFormat::Paperback };
89+
///
90+
/// assert!(b1 == b2);
91+
/// assert!(b1 != b3);
92+
/// ```
6293
///
6394
/// # Examples
6495
///
@@ -96,7 +127,32 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
96127
/// This property cannot be checked by the compiler, and therefore `Eq` implies
97128
/// `PartialEq`, and has no extra methods.
98129
///
99-
/// This trait can be used with `#[derive]`.
130+
/// ## Derivable
131+
///
132+
/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
133+
/// no extra methods, it is only informing the compiler that this is an
134+
/// equivalence relation rather than a partial equivalence relation. Note that
135+
/// the `derive` strategy requires all fields are `PartialEq`, which isn't
136+
/// always desired.
137+
///
138+
/// ## How can I implement `Eq`?
139+
///
140+
/// If you cannot use the `derive` strategy, specify that your type implements
141+
/// `Eq`, which has no methods:
142+
///
143+
/// ```
144+
/// enum BookFormat { Paperback, Hardback, Ebook }
145+
/// struct Book {
146+
/// isbn: i32,
147+
/// format: BookFormat,
148+
/// }
149+
/// impl PartialEq for Book {
150+
/// fn eq(&self, other: &Book) -> bool {
151+
/// self.isbn == other.isbn
152+
/// }
153+
/// }
154+
/// impl Eq for Book {}
155+
/// ```
100156
#[stable(feature = "rust1", since = "1.0.0")]
101157
pub trait Eq: PartialEq<Self> {
102158
// FIXME #13101: this method is used solely by #[deriving] to
@@ -190,8 +246,49 @@ impl Ordering {
190246
/// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and
191247
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
192248
///
249+
/// ## Derivable
250+
///
193251
/// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic
194252
/// ordering based on the top-to-bottom declaration order of the struct's members.
253+
///
254+
/// ## How can I implement `Ord`?
255+
///
256+
/// `Ord` requires that the type also be `PartialOrd` and `Eq` (which requires `PartialEq`).
257+
///
258+
/// Then you must define an implementation for `cmp()`. You may find it useful to use
259+
/// `cmp()` on your type's fields.
260+
///
261+
/// Here's an example where you want to sort people by height only, disregarding `id`
262+
/// and `name`:
263+
///
264+
/// ```
265+
/// use std::cmp::Ordering;
266+
///
267+
/// #[derive(Eq)]
268+
/// struct Person {
269+
/// id: u32,
270+
/// name: String,
271+
/// height: u32,
272+
/// }
273+
///
274+
/// impl Ord for Person {
275+
/// fn cmp(&self, other: &Person) -> Ordering {
276+
/// self.height.cmp(&other.height)
277+
/// }
278+
/// }
279+
///
280+
/// impl PartialOrd for Person {
281+
/// fn partial_cmp(&self, other: &Person) -> Option<Ordering> {
282+
/// Some(self.cmp(other))
283+
/// }
284+
/// }
285+
///
286+
/// impl PartialEq for Person {
287+
/// fn eq(&self, other: &Person) -> bool {
288+
/// self.height == other.height
289+
/// }
290+
/// }
291+
/// ```
195292
#[stable(feature = "rust1", since = "1.0.0")]
196293
pub trait Ord: Eq + PartialOrd<Self> {
197294
/// This method returns an `Ordering` between `self` and `other`.
@@ -242,15 +339,78 @@ impl PartialOrd for Ordering {
242339
/// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T:
243340
/// PartialOrd<V>`.
244341
///
342+
/// ## Derivable
343+
///
344+
/// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic
345+
/// ordering based on the top-to-bottom declaration order of the struct's members.
346+
///
347+
/// ## How can I implement `Ord`?
348+
///
245349
/// PartialOrd only requires implementation of the `partial_cmp` method, with the others generated
246350
/// from default implementations.
247351
///
248352
/// However it remains possible to implement the others separately for types which do not have a
249353
/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 ==
250354
/// false` (cf. IEEE 754-2008 section 5.11).
251355
///
252-
/// This trait can be used with `#[derive]`. When `derive`d, it will produce an ordering
253-
/// based on the top-to-bottom declaration order of the struct's members.
356+
/// `PartialOrd` requires your type to be `PartialEq`.
357+
///
358+
/// If your type is `Ord`, you can implement `partial_cmp()` by using `cmp()`:
359+
///
360+
/// ```
361+
/// use std::cmp::Ordering;
362+
///
363+
/// #[derive(Eq)]
364+
/// struct Person {
365+
/// id: u32,
366+
/// name: String,
367+
/// height: u32,
368+
/// }
369+
///
370+
/// impl PartialOrd for Person {
371+
/// fn partial_cmp(&self, other: &Person) -> Option<Ordering> {
372+
/// Some(self.cmp(other))
373+
/// }
374+
/// }
375+
///
376+
/// impl Ord for Person {
377+
/// fn cmp(&self, other: &Person) -> Ordering {
378+
/// self.height.cmp(&other.height)
379+
/// }
380+
/// }
381+
///
382+
/// impl PartialEq for Person {
383+
/// fn eq(&self, other: &Person) -> bool {
384+
/// self.height == other.height
385+
/// }
386+
/// }
387+
/// ```
388+
///
389+
/// You may also find it useful to use `partial_cmp()` on your type`s fields. Here
390+
/// is an example of `Person` types who have a floating-point `height` field that
391+
/// is the only field to be used for sorting:
392+
///
393+
/// ```
394+
/// use std::cmp::Ordering;
395+
///
396+
/// struct Person {
397+
/// id: u32,
398+
/// name: String,
399+
/// height: f64,
400+
/// }
401+
///
402+
/// impl PartialOrd for Person {
403+
/// fn partial_cmp(&self, other: &Person) -> Option<Ordering> {
404+
/// self.height.partial_cmp(&other.height)
405+
/// }
406+
/// }
407+
///
408+
/// impl PartialEq for Person {
409+
/// fn eq(&self, other: &Person) -> bool {
410+
/// self.height == other.height
411+
/// }
412+
/// }
413+
/// ```
254414
///
255415
/// # Examples
256416
///

0 commit comments

Comments
 (0)