1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
//! Let's `Clone` a `Cow`!
//!
//! - **Date:** February 28, 2017
//! - **Subject:** The final pieces of the story for (single-threaded) memory
//! management in Rust.
//! - [**Audio**][mp3]
//!
//! [mp3]: https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e019.mp3
//!
//! <audio style="width: 100%" title="Let's `Clone` a `Cow`!" controls preload=metadata><source src="https://www.podtrac.com/pts/redirect.mp3/cdn.newrustacean.com/file/newrustacean/e019.mp3"></audio>
//!
//!
//! Notes
//! -----
//!
//! Sometimes, we actually *do* need to copy types. Wouldn't it be nice if Rust
//! gave us a convenient way to do that when it's convenient, or when the cost
//! is low enough that the ergonomic tradeoffs are worth it? Well, perhaps
//! unsurprisingly, it does! The `Copy` and `Clone` traits, plus the `Cow` type,
//! give us everything we need!
//!
//!
//! Links
//! -----
//!
//! - [underhanded.rs]
//!
//! - The typess
//!
//! - [`std::marker::Copy`]
//!
//! - ["`Copy` types" in the book][copy-book]
//!
//! - ["Stack-Only Data: Copy" in the new book][copy-new-book]
//!
//! - [7.2.0.2 Moved and copied types]:
//!
//! > When a local variable is used as an rvalue, the variable will be copied if its
//! type implements `Copy`. All others are moved.
//!
//! - [Extended example in "Traits" section of new book][copy-traits-example-new-book]
//!
//! - [`std::clone::Clone`]
//!
//! - [`std::borrow::Cow`]
//!
//! - Default implementations
//!
//! - [discussion in the current book][default-book]
//!
//! - [discussion in the new book][default-new-book]
//!
//! - Supertraits
//!
//! - from the discussion in the reference ([6.1.9 Traits]):
//!
//! > Traits may inherit from other traits.... The syntax `Circle : Shape` means that types
//! that implement `Circle` must also have an implementation for `Shape`. Multiple
//! supertraits are separated by `+`, trait `Circle : Shape + PartialEq { }`. In an
//! implementation of `Circle` for a given type `T`, methods can refer to `Shape` methods,
//! since the typechecker checks that any type with an implementation of `Circle` also has
//! an implementation of `Shape`...
//!
//! - [discussion of trait "inheritance" in the book][trait-inheritance]
//!
//! - [discussion of trait super- and subtyping in the new book][trait-inheritance-new-book]
//! (note: still to-be-written at the time this episode was published)
//!
//! - Marker traits
//!
//! - [`std::marker`]
//!
//! - in the reference: [9 Special Traits]
//!
//! - Previous episodes on traits:
//!
//! - [e008: Just like something else][e008]
//!
//! - [e009: Composing a Rustic tune][e009]
//!
//!
//! [underhanded.rs]: https://underhanded.rs/
//! [`std::marker::Copy`]: https://doc.rust-lang.org/stable/std/marker/trait.Copy.html
//! [copy-book]: https://doc.rust-lang.org/book/ownership.html#copy-types
//! [copy-new-book]: http://rust-lang.github.io/book/ch04-01-what-is-ownership.html#stack-only-data-copy
//! [7.2.0.2 Moved and copied types]: https://doc.rust-lang.org/reference.html#moved-and-copied-types
//! [copy-traits-example-new-book]: http://rust-lang.github.io/book/ch10-02-traits.html#fixing-the-largest-function-with-trait-bounds
//! [`std::clone::Clone`]: https://doc.rust-lang.org/stable/std/clone/trait.Clone.html
//! [`std::borrow::Cow`]: https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html
//! [default-book]: https://doc.rust-lang.org/book/traits.html#default-methods
//! [default-new-book]: http://rust-lang.github.io/book/ch10-02-traits.html#default-implementations
//! [6.1.9 Traits]: https://doc.rust-lang.org/reference.html#traits
//! [trait-inheritance]: https://doc.rust-lang.org/book/traits.html#inheritance
//! [trait-inheritance-new-book]: http://rust-lang.github.io/book/ch19-00-advanced-features.html
//! [`std::marker`]: https://doc.rust-lang.org/stable/std/marker/
//! [9 Special Traits]: https://doc.rust-lang.org/reference.html#special-traits
//! [e008]: https://www.newrustacean.com/show_notes/e008/
//! [e009]: https://www.newrustacean.com/show_notes/e009/
//!
//!
//! Sponsors
//! --------
//!
//!
//! - Aleksey Pirogov
//! - Andreas Fischer
//! - Andrew Thompson
//! - Austin LeSure
//! - Ben Whitley
//! - [Charlie Egan]
//! - [Chris Palmer]
//! - [Christopher Giffard]
//! - [Daniel Collin]
//! - [Derek Morr]
//! - [Jakub "Limeth" Hlusička]
//! - Jordan Henderson
//! - [Jupp Müller]
//! - Keith Gray
//! - Lachlan Collins
//! - Luca Schmid
//! - Matt Rudder
//! - Matthew Piziak
//! - [Max Jacobson]
//! - Micael Bergeron
//! - Ovidiu Curcan
//! - [Pascal Hertleif]
//! - Peter Tillemans
//! - Philipp Keller
//! - Ralph Giles ("rillian")
//! - Raph Levien
//! - reddraggone9
//! - Steven Murawski
//! - [Stuart Hinson]
//! - Tyler Harper
//! - Vesa Kaihlavirta
//! - Vlad Bezden
//! - [William Roe]
//! - Zaki
//!
//! [Charlie Egan]: https://charlieegan3.com
//! [Chris Palmer]: http://red-oxide.org/
//! [Christopher Giffard]: http://blog.cgiffard.com
//! [Daniel Collin]: https://twitter.com/daniel_collin
//! [Derek Morr]: https://twitter.com/derekmorr
//! [Jakub "Limeth" Hlusička]: https://github.com/Limeth
//! [Jupp Müller]: https://de.linkedin.com/in/juppm
//! [Max Jacobson]: https://twitter.com/maxjacobson
//! [Pascal Hertleif]: https://pascalhertleif.de/
//! [Philipp Keller]: https://twitter.com/hansapla
//! [Stuart Hinson]: http://stuarth.github.io/
//! [William Roe]: http://willroe.me
//!
//! (Thanks to the couple people donating who opted out of the reward tier, as
//! well. You know who you are!)
//!
//! ### Become a sponsor
//!
//! - <a href="https://www.patreon.com/newrustacean" rel="payment">Patreon</a>
//! - [Venmo](https://venmo.com/chriskrycho)
//! - [Dwolla](https://www.dwolla.com/hub/chriskrycho)
//! - [Cash.me](https://cash.me/$chriskrycho)
//! - [Flattr](https://flattr.com/profile/chriskrycho)
//! - [PayPal.me](https://paypal.me/chriskrycho)
//!
//!
//! Contact
//! -------
//!
//! - New Rustacean:
//! + Twitter: [@newrustacean](https://www.twitter.com/newrustacean)
//! + Email: [hello@newrustacean.com](mailto:hello@newrustacean.com)
//! - Chris Krycho
//! + GitHub: [chriskrycho](https://github.com/chriskrycho)
//! + Twitter: [@chriskrycho](https://www.twitter.com/chriskrycho)
/// A non-copyable point type
///
/// # Examples
///
/// ```rust,ignore
/// # use show_notes::e019::ANoCopyOrClonePoint;
/// let a_point = ANoCopyOrClonePoint::origin();
/// let moved_point = a_point; // <- moves the value
/// println!("{:?}", a_point); // <- so this is a problem!
/// println!("{:?}", moved_point)
/// ```
///
/// The output is just what we would expect from the discussion on the show:
///
/// ```plain
/// error[E0382]: use of moved value: `a_point`
/// --> <anon>:6:18
/// |
/// 5 | let moved_point = a_point; // <- moves the value
/// | ----------- value moved here
/// 6 | println!("{:?}", a_point); // <- so this is a problem!
/// | ^^^^^^^ value used here after move
/// |
/// = note: move occurs because `a_point` has type `show_notes::e019::ANoCopyOrClonePoint`, which does not implement the `Copy` trait
/// ```
///
/// If we comment the offending line out, however, it compiles just fine.
///
/// ```rust
/// # use show_notes::e019::ANoCopyOrClonePoint;
/// let a_point = ANoCopyOrClonePoint::origin();
/// let moved_point = a_point;
/// // println!("{:?}", a_point);
/// println!("{:?}", moved_point); // <- not a problem!
/// ```
///
/// [(You can confirm this in the playground.)][playground]
///
/// [playground]: https://is.gd/PZBWw0
#[derive(Debug)]
pub struct ANoCopyOrClonePoint {
x: f64,
y: f64,
z: f64,
}
impl ANoCopyOrClonePoint {
/// Generate a point at 0, 0, 0
pub fn origin() -> ANoCopyOrClonePoint {
ANoCopyOrClonePoint {
x: 0.0,
y: 0.0,
z: 0.0,
}
}
}
/// A struct which implements `Clone` but not `Copy`.
///
/// # Examples
///
/// If you don't do anything, the item will be moved on assignment:
///
/// ```rust,ignore
/// # use show_notes::e019::BJustClonePoint;
/// let a_point = BJustClonePoint::origin();
/// let cloned_point = a_point; // <- moves the value
/// println!("{:?}", a_point); // <- compile error!
/// println!("{:?}", cloned_point);
/// ```
///
/// The output is just what we would expect from the discussion on the show:
///
/// ```plain
/// error[E0382]: use of moved value: `a_point`
/// --> <anon>:6:18
/// |
/// 5 | let cloned_point = a_point; // <- moves the value
/// | ------------ value moved here
/// 6 | println!("{:?}", a_point); // <- compile error!
/// | ^^^^^^^ value used here after move
/// |
/// = note: move occurs because `a_point` has type `show_notes::e019::BJustClonePoint`, which does not implement the `Copy` trait
/// ```
///
///
/// But you can manually call the `clone` method, and it will work:
///
/// ```rust
/// # use show_notes::e019::BJustClonePoint;
/// let a_point = BJustClonePoint::origin();
/// let cloned_point = a_point.clone();
/// println!("{:?}", a_point); // <- not a problem
/// println!("{:?}", cloned_point);
/// ```
#[derive(Clone, Debug)]
pub struct BJustClonePoint {
x: f64,
y: f64,
z: f64,
}
impl BJustClonePoint {
pub fn origin() -> BJustClonePoint {
BJustClonePoint {
x: 0.0,
y: 0.0,
z: 0.0,
}
}
}
/// A struct with identical behavior to `ANoCopyOrClonePoint`, except with `Copy`.
///
/// Note that we have `Clone` as well as `Copy` here---we have to, since
/// `Clone` is a supertrait for `Copy`.
///
/// # Examples
///
/// Note that this is just like the non-compiling example in [`ANoCopyOrClonePoint`], but because
/// `CCopyPoint` implements `Copy`, the line which previously caused a compile
/// error now works without any issue.
///
/// ```rust
/// # use show_notes::e019::CCopyPoint;
/// let a_point = CCopyPoint::origin();
/// let copied_point = a_point;
/// println!("{:?}", a_point); // <- not a problem
/// println!("{:?}", copied_point)
/// ```
///
/// [`ANoCopyOrClonePoint`]: /show_notes/e019/struct.ANoCopyOrClonePoint.html
#[derive(Clone, Copy, Debug)]
pub struct CCopyPoint {
x: f64,
y: f64,
z: f64,
}
impl CCopyPoint {
/// Generate a point at 0, 0, 0
pub fn origin() -> CCopyPoint {
CCopyPoint {
x: 0.0,
y: 0.0,
z: 0.0,
}
}
}
/// The `Cow` type can wrap around other types and make them "reusable".
///
/// Note that the body of this function is identical with that of the body of
/// the example below.
///
/// # Examples
///
/// We'll reuse the `BJustClonePoint` since `Cow::Owned` requires that the
/// underlying type implement `Clone`.
///
/// ```rust
/// # use std::borrow::Cow;
/// # use show_notes::e019::{BJustClonePoint,demonstrate_cow};
/// let a_point = Cow::Owned(BJustClonePoint::origin());
/// demonstrate_cow(&a_point);
/// ```
///
/// Note that even though `demonstrate_cow` takes a reference to
/// `BJustClonePoint`, we can pass it the `Cow` instance; this is where the
/// `Deref` implementation on `Cow` comes in handy.
pub fn demonstrate_cow(_point: &BJustClonePoint) {}
/// What if we need a mutable reference to the wrapped type?
///
/// # Examples
///
/// We can get a mutable reference to the wrapped item, even if the wrapped item
/// isn't itself mutable, as long as it's `Clone`-able. In this case, we're
/// making a copy---this is explicit in the `to_mut()` call. If the underlying
/// item isn't mutably accessible, we'll just get a mutable copy.
///
/// ```rust
/// # use std::borrow::Cow;
/// # use show_notes::e019::{BJustClonePoint,demonstrate_mut_cow};
/// let mut a_point: Cow<BJustClonePoint> = Cow::Owned(BJustClonePoint::origin());
/// demonstrate_mut_cow(a_point.to_mut());
/// ```
pub fn demonstrate_mut_cow(_point: &mut BJustClonePoint) {}