]> git.lizzy.rs Git - rust.git/commitdiff
Add std::mem::take as suggested in #61129
authorJon Gjengset <jon@thesquareplanet.com>
Fri, 24 May 2019 17:52:06 +0000 (13:52 -0400)
committerJon Gjengset <jon@thesquareplanet.com>
Wed, 29 May 2019 22:14:55 +0000 (18:14 -0400)
The name `swap_default` was suggested but rejected. @SimonSapin observed
that this operation isn't really a `swap` in the same sense as
`mem::swap`; it is a `replace`. Since `replace_default` is a bit
misleading, the "correct" name would be `replace_with_default`, which is
quite verbose.

@czipperz observed that we have precedence for using `take` to refer to
methods that replace with `Default` in `Cell::take` and `Option::take`,
so this reverts commit 99c00591c29b472c8a87c4a9342d0e0c508647a3 to
return to the original `take` method name.

The name `replace_with_default` was suggested, but was deemed too
verbose, especially given that we use `take` for methods that replace
with `Default` elsewhere.

src/libcore/mem/mod.rs

index 91449f09936aa2597487e6f5aa10e3cb1893df3b..c4d8e40a5e682f0e03d3a78bdd97bc099e418b1e 100644 (file)
@@ -503,6 +503,61 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
     }
 }
 
     }
 }
 
+/// Replace `dest` with the default value of `T`, and return the previous `dest` value.
+///
+/// # Examples
+///
+/// A simple example:
+///
+/// ```
+/// use std::mem;
+///
+/// let mut v: Vec<i32> = vec![1, 2];
+///
+/// let old_v = mem::take(&mut v);
+/// assert_eq!(vec![1, 2], old_v);
+/// assert!(v.is_empty());
+/// ```
+///
+/// `take` allows taking ownership of a struct field by replacing it with an "empty" value.
+/// Without `take` you can run into issues like these:
+///
+/// ```compile_fail,E0507
+/// struct Buffer<T> { buf: Vec<T> }
+///
+/// impl<T> Buffer<T> {
+///     fn get_and_reset(&mut self) -> Vec<T> {
+///         // error: cannot move out of dereference of `&mut`-pointer
+///         let buf = self.buf;
+///         self.buf = Vec::new();
+///         buf
+///     }
+/// }
+/// ```
+///
+/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset
+/// `self.buf`. But `take` can be used to disassociate the original value of `self.buf` from
+/// `self`, allowing it to be returned:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// use std::mem;
+///
+/// # struct Buffer<T> { buf: Vec<T> }
+/// impl<T> Buffer<T> {
+///     fn get_and_reset(&mut self) -> Vec<T> {
+///         mem::take(&mut self.buf)
+///     }
+/// }
+/// ```
+///
+/// [`Clone`]: ../../std/clone/trait.Clone.html
+#[inline]
+#[unstable(feature = "mem_take", issue = "61129")]
+pub fn take<T: Default>(dest: &mut T) -> T {
+    replace(dest, T::default())
+}
+
 /// Moves `src` into the referenced `dest`, returning the previous `dest` value.
 ///
 /// Neither value is dropped.
 /// Moves `src` into the referenced `dest`, returning the previous `dest` value.
 ///
 /// Neither value is dropped.