@@ -1402,6 +1402,74 @@ pub struct LayoutRef<A, D>
1402
1402
strides : D ,
1403
1403
}
1404
1404
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.
1405
1473
#[ repr( transparent) ]
1406
1474
pub struct ArrayRef < A , D > ( LayoutRef < A , D > ) ;
1407
1475
0 commit comments