@@ -1402,6 +1402,74 @@ pub struct LayoutRef<A, D>
14021402 strides : D ,
14031403}
14041404
1405+ /// A reference to an *n*-dimensional array whose data is safe to read and write.
1406+ ///
1407+ /// This type's relationship to [`ArrayBase`] can be thought of a bit like the
1408+ /// relationship between [`Vec`] and [`std::slice`]: it represents a look into the
1409+ /// array, and is the [`Deref`](std::ops::Deref) target for owned, shared, and viewed
1410+ /// arrays. Most functionality is implemented on `ArrayRef`, and most functions
1411+ /// should take `&ArrayRef` instead of `&ArrayBase`.
1412+ ///
1413+ /// ## Relationship to Views
1414+ /// `ArrayRef` and [`ArrayView`] are very similar types: they both represent a
1415+ /// "look" into an array. There is one key difference: views have their own
1416+ /// shape and strides, while `ArrayRef` just points to the shape and strides of
1417+ /// whatever array it came from.
1418+ ///
1419+ /// As an example, let's write a function that takes an array, trims it
1420+ /// down to a square in-place, and then returns the sum:
1421+ /// ```rust
1422+ /// use std::cmp;
1423+ /// use std::ops::Add;
1424+ ///
1425+ /// use ndarray::{ArrayRef2, array, s};
1426+ /// use num_traits::Zero;
1427+ ///
1428+ /// fn square_and_sum<A>(arr: &mut ArrayRef2<A>) -> A
1429+ /// where A: Clone + Add<Output = A> + Zero
1430+ /// {
1431+ /// let side_len = cmp::min(arr.nrows(), arr.ncols());
1432+ /// arr.slice_collapse(s![..side_len, ..side_len]);
1433+ /// arr.sum()
1434+ /// }
1435+ ///
1436+ /// let mut arr = array![
1437+ /// [ 1, 2, 3],
1438+ /// [ 4, 5, 6],
1439+ /// [ 7, 8, 9],
1440+ /// [10, 11, 12]
1441+ /// ];
1442+ /// // Take a view of the array, excluding the first column
1443+ /// let mut view = arr.slice_mut(s![.., 1..]);
1444+ /// let sum_view = square_and_sum(&mut view);
1445+ /// assert_eq!(sum_view, 16);
1446+ /// assert_eq!(view.ncols(), 2usize); // The view has changed shape...
1447+ /// assert_eq!(view.nrows(), 2usize);
1448+ /// assert_eq!(arr.ncols(), 3usize); // ... but the original array has not
1449+ /// assert_eq!(arr.nrows(), 4usize);
1450+ ///
1451+ /// let sum_all = square_and_sum(&mut arr);
1452+ /// assert_eq!(sum_all, 45);
1453+ /// assert_eq!(arr.ncols(), 3usize); // Now the original array has changed shape
1454+ /// assert_eq!(arr.nrows(), 3usize); // because we passed it directly to the function
1455+ /// ```
1456+ /// Critically, we can call the same function on both the view and the array itself.
1457+ /// We can see that, because the view has its own shape and strides, "squaring" it does
1458+ /// not affect the shape of the original array. Those only change when we pass the array
1459+ /// itself into the function.
1460+ ///
1461+ /// Also notice that the output of `slice_mut` is a *view*, not an `ArrayRef`.
1462+ /// This is where the analogy to `Vec`/`slice` breaks down a bit: due to limitations of
1463+ /// the Rust language, `ArrayRef` *cannot* have a different shape / stride from the
1464+ /// array from which it is dereferenced. So slicing still produces an `ArrayView`,
1465+ /// not an `ArrayRef`.
1466+ ///
1467+ /// ## Uniqueness
1468+ /// `ndarray` has copy-on-write shared data; see [`ArcArray`], for example.
1469+ /// When a copy-on-write array is passed to a function that takes `ArrayRef` as mutable
1470+ /// (i.e., `&mut ArrayRef`, like above), that array will be un-shared when it is dereferenced
1471+ /// into `ArrayRef`. In other words, having a `&mut ArrayRef` guarantees that the underlying
1472+ /// data is un-shared and safe to write to.
14051473#[ repr( transparent) ]
14061474pub struct ArrayRef < A , D > ( LayoutRef < A , D > ) ;
14071475
0 commit comments