1

As the title reads, how would I go about doing this?

fn foo(array: &[u32; 10]) -> &[u32; 5] {
    &array[0..5]
}

Compiler error

error[E0308]: mismatched types
 --> src/main.rs:2:5
  |
2 |     &array[0..5]
  |     ^^^^^^^^^^^^ expected array of 5 elements, found slice
  |
  = note: expected type `&[u32; 5]`
  = note:    found type `&[u32]`
2
  • You'll have to provide a slice instead (or a new array instance). AFAIK a borrowed slice cannot be safely converted to a borrowed array. Commented Nov 8, 2016 at 14:00
  • The length goes after the type i.e. &[u32; 10] although I think you'll have to return an unsized slice: fn foo(array: &[u32; 10]) -> &[u32] { &array[0..5] } Commented Nov 8, 2016 at 14:01

2 Answers 2

2

arrayref implements a safe interface for doing this operation, using macros (and compile-time constant slicing bounds, of course).

Their readme explains

The goal of arrayref is to enable the effective use of APIs that involve array references rather than slices, for situations where parameters must have a given size.

and

let addr: &[u8; 16] = ...;
let mut segments = [0u16; 8];
// array-based API with arrayref
for i in 0 .. 8 {
    segments[i] = read_u16_array(array_ref![addr,2*i,2]);
}

Here the array_ref![addr,2*i,2] macro allows us to take an array reference to a slice consisting of two bytes starting at 2*i. Apart from the syntax (less nice than slicing), it is essentially the same as the slice approach. However, this code makes explicit the need for precisely two bytes both in the caller, and in the function signature.

Sign up to request clarification or add additional context in comments.

Comments

1

Stable Rust

It's not possible to do this using only safe Rust. To understand why, it's important to understand how these types are implemented. An array is guaranteed to have N initialized elements. It cannot get smaller or larger. At compile time, those guarantees allow the size aspect of the array to be removed, and the array only takes up N * sizeof(element) space.

That means that [T; N] and [T; M] are different types (when N != M) and you cannot convert a reference of one to the other.

The idiomatic solution is to use a slice instead:

fn foo(array: &[u32; 10]) -> &[u32] {
    &array[0..5]
}

A slice contains a pointer to the data and the length of the data, thus moving that logic from compile time to run time.

Nightly Rust

You can perform a runtime check that the slice is the correct length and convert it to an array in one step:

#![feature(try_from)]

use std::convert::TryInto;

fn foo(array: &[u32; 10]) -> &[u32; 5] {
    array[0..5].try_into().unwrap()
}

fn main() {}

Unsafe Rust

Because someone might want to do this the unsafe way in an earlier version of Rust, I'll present code based on the standard library implementation:

fn foo(array: &[u32; 10]) -> &[u32; 5] {
    let slice = &array[0..5];

    if slice.len() == 5 {
        let ptr = slice.as_ptr() as *const [u32; 5];
        unsafe { &*ptr }
    } else {
        panic!("Needs to be length 5")
    }
}

fn main() {
    let input = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let output = foo(&input);
    println!("{:?}", output);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.