# \`slice\` lacks \`get\_array\_ref\` functionality

**URL:** <https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966>\
**Category:** Uncategorized\
**Created:** [January 16, 2022, 3:13pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966 "2022-01-16T15:13:04Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![pmnoxx](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pmnoxx/32/8960_2.png) [@pmnoxx](https://internals.rust-lang.org/u/pmnoxx)\
**Post date:** [January 16, 2022, 3:13pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/1 "2022-01-16T15:13:04Z")

</div>

I noticed that `impl<T> [T]` implements `get` function. This allow to get elements in a range as slice. For example `[200,200,0,0,1,1].get(..4)`, unfortunately, the return type is a slice, rather than array ref.

I'm looking for a way, to get this slice as a fixed size array ref. Ideally I would like to write the code this like

```rust
let _: Option<[u8; 4]> = [200,200,0,0,1,1].get_array_ref<4>(0);
let _: Option<[u8; 1]> = [200,200,0,0,1,1].get_array_ref<1>(4);

```

Current `get` api looks like this:

```rust
   pub fn get<I>(&self, index: I) -> Option<&I::Output> where I: SliceIndex<Self>;

```

It would be a good idea to add the following api.

```rust
#[lang = "slice"]
#[cfg(not(test))]
impl<T> [T] {
    pub fn get_array_ref<const N: usize>(&self, index: usize) -> Option<&[T; N];
}

```

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [January 16, 2022, 4:04pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/2 "2022-01-16T16:04:23Z")

</div>

> [@pmnoxx](#):
>
> I'm looking for a way, to get this slice as a fixed size array ref

`&[T; N]` implements `TryFrom<&[T]>`, so you can use that (or the equivalent `TryInto` impl) to get an array ref from a slice (though you have to first slice it to the right length).

---

<div class="post-metadata">

**Author:** ![pmnoxx](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pmnoxx/32/8960_2.png) [@pmnoxx](https://internals.rust-lang.org/u/pmnoxx)\
**Post date:** [January 16, 2022, 4:24pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/3 "2022-01-16T16:24:02Z")

</div>

> [@SkiFire13](#):
>
> > [@pmnoxx](#):
> >
> > I'm looking for a way, to get this slice as a fixed size array ref
> 
> `&[T; N]` implements `TryFrom<&[T]>` , so you can use that (or the equivalent `TryInto` impl) to get an array ref from a slice (though you have to first slice it to the right length).

Yes, technically, it's possible to write it as a single line:

```rust
   let _x: Option<&[u8; 4]> =
            [200u8, 200, 0, 0, 1, 1].get(..4).map(|x| <&[u8; 4]>::try_from(x).ok()).flatten();

```

That's a big ugly though.

---

<div class="post-metadata">

**Author:** ![jplatte](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jplatte/32/11437_2.png) [@jplatte](https://internals.rust-lang.org/u/jplatte)\
**Post date:** [January 16, 2022, 4:48pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/4 "2022-01-16T16:48:11Z")

</div>

> [@pmnoxx](#):
>
> Yes, technically, it's possible to write it as a single line: [...]

You don't need the type annotation and `map` + `flatten` on an Option can be simplified to just `and_then`. So you can get away with less boilerplate, though of course a dedicated method would still be shorter.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [January 16, 2022, 5:38pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/5 "2022-01-16T17:38:38Z")

</div>

Your proposed API is a index-length API. While this is unavoidable (since the length needs to be const, and the index shouldn't need to be), it's definitely not immediately clear.

A currently available unstable option is [`array_windows`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.array_windows).

```rust
fn get_array_ref<const N: usize>(this: &[T], index: usize) -> Option<&[T; N]> {
    this.array_windows::<N>().nth(index)
}

```

[https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=17817ba390a3ef938e3d07076676630d](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=17817ba390a3ef938e3d07076676630d)

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [January 16, 2022, 8:40pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/6 "2022-01-16T20:40:45Z")

</div>

> [@pmnoxx](#):
>
> For example `[200,200,0,0,1,1].get(..4)` , unfortunately, the return type is a slice, rather than array ref.

There's a wide variety of unstable array-returning functions in nightly, as this is still an evolving area.

For example, one way to do that would be `.as_chunks().0.get(0)`.

---

<div class="post-metadata">

**Author:** ![frank-king](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/frank-king/32/8765_2.png) [@frank-king](https://internals.rust-lang.org/u/frank-king)\
**Post date:** [January 18, 2022, 1:00pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/7 "2022-01-18T13:00:01Z")

</div>

Is it possible to do this? (But might require more functioning of const generics)

```rust
 // Make literals of range to be `ConstRange`, and allow it coerce to `Range<uize>`.
ConstRange<Idx, const S: Idx, const E: Idx>;

impl<T, const N: usize, const S: usize, const E: usize> SliceIndex<[T; N]>
    for ConstRange<usize, S, E>
where
    S < E,
    S < N,
    E <= N,
{
    type Output = [T; E - S];
    fn index(self, slice: &[T; N]) -> &Self::Output {
        unsafe { self.get_unchecked(slice)) as &[T; E - S] }
    }
    unsafe fn get_unchecked(self, slice: *const [T; N]) -> *const Self::Output {
        slice.as_ptr().add(S) as *const [T; E - S]
    }
    // impl other functions similarly
}

```

And then, it is possible to use it like this

```rust
let arr = [0, 1, 2, 3, 4];
let sub_array: [i32; 2] = arr[0..2];

```

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [January 18, 2022, 1:35pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/8 "2022-01-18T13:35:32Z")

</div>

With `adt_const_params` you can use `Range` itself. But to return an array based on that requires the full `generic_const_exprs` feature. And using every possible range (`Range`, `RangeInclusive`, `RangeTo`, etc.) isn't possible even then, unless we'll have some kind of generics-over-const-parameters (i.e. `fn foo<T: Trait, const C: T>()`).

```rust
#![feature(adt_const_params, generic_const_exprs)]

use std::ops::Range;

pub const fn range_size(range: Range<usize>) -> usize {
    range.end - range.start
}

pub fn slice_get_array<T, const RANGE: Range<usize>>(slice: &[T]) -> &[T; range_size(RANGE)] {
    unsafe { &*(&slice[RANGE] as *const [T] as *const _) }
}

```

[Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=dea8a48938842cef804083f6462fed0c).

---

<div class="post-metadata">

**Author:** ![frank-king](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/frank-king/32/8765_2.png) [@frank-king](https://internals.rust-lang.org/u/frank-king)\
**Post date:** [January 18, 2022, 1:42pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/9 "2022-01-18T13:42:25Z")

</div>

It's cool! But it could be even better if your version `fn slice_get_array` can be put into a trait so that slicing on arrays can get an array, too, if the index `Range<usize>` is `const` (instead of a slice).

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [January 18, 2022, 1:47pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/10 "2022-01-18T13:47:30Z")

</div>

```rust
pub trait SliceExt {
    type Item;
    fn get_array<const RANGE: Range<usize>>(&self) -> &[Self::Item; range_size(RANGE)];
    fn get_array_mut<const RANGE: Range<usize>>(&mut self) -> &mut [Self::Item; range_size(RANGE)];
}

impl<T> SliceExt for [T] {
    type Item = T;
    fn get_array<const RANGE: Range<usize>>(&self) -> &[T; range_size(RANGE)] {
        unsafe { &*(&self[RANGE] as *const [T] as *const _) }
    }
    fn get_array_mut<const RANGE: Range<usize>>(&mut self) -> &mut [T; range_size(RANGE)] {
        unsafe { &mut *(&mut self[RANGE] as *mut [T] as *mut _) }
    }
}

impl<T, const N: usize> SliceExt for [T; N] {
    type Item = T;
    fn get_array<const RANGE: Range<usize>>(&self) -> &[T; range_size(RANGE)] {
        unsafe { &*(&self[RANGE] as *const [T] as *const _) }
    }
    fn get_array_mut<const RANGE: Range<usize>>(&mut self) -> &mut [T; range_size(RANGE)] {
        unsafe { &mut *(&mut self[RANGE] as *mut [T] as *mut _) }
    }
}

fn main() {
    let slice: &[i32] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let arr: &[i32; 3] = slice.get_array::<{ 1..4 }>();
    // let arr: &[i32; 4] = slice.get_array::<{ 1..4 }>();
    dbg!(arr);
}

```

[Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=b7abe393fbbec82b80ded6f91cc96313).

---

<div class="post-metadata">

**Author:** ![frank-king](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/frank-king/32/8765_2.png) [@frank-king](https://internals.rust-lang.org/u/frank-king)\
**Post date:** [January 18, 2022, 1:53pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/11 "2022-01-18T13:53:50Z")

</div>

> [@chrefr](#):
>
> ```rust
> let arr: &[i32; 3] = slice.get_array::<{ 1..4 }>();
> 
> ```

Actually, I hope there is `let arr: &[i32; 3] = slice[1..4];` in the future (maybe in Rust 2024 or something else).

It is straightforward and all bound checks can be done in compile time.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [January 18, 2022, 1:58pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/12 "2022-01-18T13:58:00Z")

</div>

I'm not even sure that adding a method to the standard library is good (though it can live inside an external crate), but I'm pretty sure that re-using the existing syntax is a _very bad_ idea. Values that affect types? And if later I'll store the range in a variable, will I need to change the type in every place too?

---

<div class="post-metadata">

**Author:** ![frank-king](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/frank-king/32/8765_2.png) [@frank-king](https://internals.rust-lang.org/u/frank-king)\
**Post date:** [January 18, 2022, 2:16pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/13 "2022-01-18T14:16:22Z")

</div>

> [@chrefr](#):
>
> re-using the existing syntax is a _very bad_ idea

I agree with you. How about making a `&[T]` convertible (by coercing?) to a `&[T; N]` in a `const` context? Since the length of slice must be known to the compiler in a `const` context.

EDIT: or allow `&[T] as &[T; N]` if `&[T]` is `const`.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [April 18, 2022, 2:16pm UTC](https://internals.rust-lang.org/t/slice-lacks-get-array-ref-functionality/15966/14 "2022-04-18T14:16:32Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
