diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs
index ffd571977..c45799e5f 100644
--- a/src/impl_owned_array.rs
+++ b/src/impl_owned_array.rs
@@ -1,5 +1,44 @@
use imp_prelude::*;
+/// Methods specific to `Array0`.
+///
+/// ***See also all methods for [`ArrayBase`]***
+///
+/// [`ArrayBase`]: struct.ArrayBase.html
+impl Array {
+ /// Returns the single element in the array without cloning it.
+ ///
+ /// ```
+ /// use ndarray::{arr0, Array0};
+ ///
+ /// // `Foo` doesn't implement `Clone`.
+ /// #[derive(Debug, Eq, PartialEq)]
+ /// struct Foo;
+ ///
+ /// let array: Array0 = arr0(Foo);
+ /// let scalar: Foo = array.into_scalar();
+ /// assert_eq!(scalar, Foo);
+ /// ```
+ pub fn into_scalar(mut self) -> A {
+ let size = ::std::mem::size_of::();
+ if size == 0 {
+ // Any index in the `Vec` is fine since all elements are identical.
+ self.data.0.remove(0)
+ } else {
+ // Find the index in the `Vec` corresponding to `self.ptr`.
+ // (This is necessary because the element in the array might not be
+ // the first element in the `Vec`, such as if the array was created
+ // by `array![1, 2, 3, 4].slice_move(s![2])`.)
+ let first = self.ptr as usize;
+ let base = self.data.0.as_ptr() as usize;
+ let index = (first - base) / size;
+ debug_assert_eq!((first - base) % size, 0);
+ // Remove the element at the index and return it.
+ self.data.0.remove(index)
+ }
+ }
+}
+
/// Methods specific to `Array`.
///
/// ***See also all methods for [`ArrayBase`]***
diff --git a/src/lib.rs b/src/lib.rs
index 5bf56674b..ed60d55d2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -855,11 +855,11 @@ pub type Ixs = isize;
///
///
///
-/// ### Conversions Between Arrays and `Vec`s/Slices
+/// ### Conversions Between Arrays and `Vec`s/Slices/Scalars
///
-/// This is a table of the safe conversions between arrays and `Vec`s/slices.
-/// Note that some of the return values are actually `Result`/`Option` wrappers
-/// around the indicated output types.
+/// This is a table of the safe conversions between arrays and
+/// `Vec`s/slices/scalars. Note that some of the return values are actually
+/// `Result`/`Option` wrappers around the indicated output types.
///
/// Input | Output | Methods
/// ------|--------|--------
@@ -875,6 +875,7 @@ pub type Ixs = isize;
/// `&mut ArrayBase` | `&mut [A]` | [`.as_slice_mut()`](#method.as_slice_mut)[2](#req_contig_std), [`.as_slice_memory_order_mut()`](#method.as_slice_memory_order_mut)[3](#req_contig)
/// `ArrayView` | `&[A]` | [`.into_slice()`](type.ArrayView.html#method.into_slice)
/// `ArrayViewMut` | `&mut [A]` | [`.into_slice()`](type.ArrayViewMut.html#method.into_slice)
+/// `Array0` | `A` | [`.into_scalar()`](type.Array.html#method.into_scalar)
///
/// 1Returns the data in memory order.
///
diff --git a/tests/array.rs b/tests/array.rs
index 0621fa322..a075246f1 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -928,6 +928,21 @@ fn as_slice_memory_order()
assert!(a != b, "{:?} != {:?}", a, b);
}
+#[test]
+fn array0_into_scalar() {
+ // With this kind of setup, the `Array`'s pointer is not the same as the
+ // underlying `Vec`'s pointer.
+ let a: Array0 = array![4, 5, 6, 7].into_subview(Axis(0), 2);
+ assert_ne!(a.as_ptr(), a.into_raw_vec().as_ptr());
+ // `.into_scalar()` should still work correctly.
+ let a: Array0 = array![4, 5, 6, 7].into_subview(Axis(0), 2);
+ assert_eq!(a.into_scalar(), 6);
+
+ // It should work for zero-size elements too.
+ let a: Array0<()> = array![(), (), (), ()].into_subview(Axis(0), 2);
+ assert_eq!(a.into_scalar(), ());
+}
+
#[test]
fn owned_array1() {
let mut a = Array::from_vec(vec![1, 2, 3, 4]);