Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow slicing to fixed-length arrays #1833

Open
torkleyy opened this issue Dec 28, 2016 · 5 comments
Open

Allow slicing to fixed-length arrays #1833

torkleyy opened this issue Dec 28, 2016 · 5 comments
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@torkleyy
Copy link

torkleyy commented Dec 28, 2016

I think it would be nice to do something like that:

let x = [1, 2, 3, 4];
let y = x[1..2];

Why isn't y of type [i32; 2] now?

I wanted to convert a [f32; 16] to an [[f32; 4]; 4], however there seems to be no easy way to do that.

@SimonSapin
Copy link
Contributor

x[1..2] and x[1..4] are both calls to Trait std::ops::Index::<Range<usize>>::index. The type parameter Range<usize> is the same is both cases, therefore the associated type Index::Output has to be the same, therefore the return type of the index method has to be the same.

So it doesn’t work with the slicing/indexing syntax, but I agree that it would be nice to have some API that does this. However, doing it "right" likely requires type-lever integers. With made-up syntax, it could look like:

impl<T> [T] {
    pub fn as_array<int N>(&self) -> &[T; N] {
        assert_eq!(self.len(), N);
        let ptr = self.as_ptr() as *const [T; N];
        unsafe { &*ptr }
    }
}

In the meantime, you can fake it with a macro like the one used in ring.

I wanted to convert a [f32; 16] to an [[f32; 4]; 4]

If the size is fixed for your program that’s even easier. You can use a similar pattern, casting raw pointers:

fn to_4x4(array: &[f32; 16]) -> &[[f32; 4]; 4] {
    unsafe { &*(array as *const _ as *const _) }
}

However this case is more complicated than as_array above since the slice item type is not the same in and out.

@torkleyy
Copy link
Author

Ah! Thanks for your solution. Yeah, it would be really handy to have these type-level integers.

@burdges
Copy link

burdges commented Dec 28, 2016

Use the arrayref crate until we get type-level integers or similar.

@nrc nrc added the T-lang Relevant to the language team, which will review and decide on the RFC. label Jan 4, 2017
@LHolten
Copy link

LHolten commented Jan 18, 2024

How about allowing something similar to zig?
let y: [u8; 4] = x[5..][..4]

@SimonSapin
Copy link
Contributor

Update since my 7-years-old comment above: we now have const generics, and these impls in the standard library:

impl<T, const N: usize> TryFrom<&[T]> for &[T; N]
impl<T, const N: usize> TryFrom<&[T]> for [T; N] where T: Copy

So you can write:

let y: [_; 4] = (&x[5..][..4]).try_into().unwrap();

Maybe with a helper function:

fn const_slice_to<T, const N: usize>(x: &[T]) -> &[T; N] {
    x.try_into().unwarp()
}

let y: [_; 4] = *const_slice_to(x);  // or:
let y = *const_slice_to::<4>(x);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

5 participants