Home > Back-end >  Get const array length in Rust
Get const array length in Rust

Time:07-12

Since Rust array length is known at compile time, how do I get that length as a constant integer? It is possible to get the non-const len() of the slice corresponding to the whole array. It doesn't seem like rust has begin and end iterators like in c , and it's not clear to me if I can get the byte length and divide it by the byte size of elements. I'm still a noob at Rust, so it's possible I'm missing something but I've been looking for the past few days for a way to do this. I'm aware that cloning an array is possible, but that's only useful if I want a clone, and iterating over every element of the array is slow compared to just getting the length from the type of the array. How can I do this? The Rust documentation says that the type signature of arrays is [ele_type; ele_number], so the compiler does keep track of the length of arrays after creation. I'm aware that std::any::type_name::() can be used to print the type of a variable, but its output isn't const.

I am aware of a related question already posed, but my question isn't answered by existing answers and the question is old (from 2017) so things may have changed and it would not likely be suggested to people.

Edit to add example:

fn main()
{
    let test_arr = [0.f64; 10];
    do_something(test_arr);

}

fn do_something<const C: usize>(array: [f64; C])
{
    // This causes an error because len() returns a nonconst uint,
    // and so can’t be used to create new arrays
    // C can also not be used because it counts as external
    let triple_size_array = [f64; array.len()*3];
}

Edit 2: To clarify, it is possible to do array = [f64; C]; directly, but there's other things that can't be done. As shown below, I can't do any integer math with C to define an array of a different size, I can only use the generic parameter to define an array directly.

13 | fn ftcs_update<const C: usize>(u: &[f64;C], f: fn(f64)->f64, l: f64)
   |                      - const parameter from outer function
14 | {
15 |     const grid_size: usize = C;
   |                              ^ use of generic parameter from outer function

error: aborting due to previous error

For more information about this error, try `rustc --explain E0401`.
error: generic parameters may not be used in const operations
  --> main.rs:16:22
   |
16 |     let u_new = [0.; C*3];
   |                      ^ cannot perform const operation using `C`
   |
   = help: const parameters may only be used as standalone arguments, i.e. `C`

CodePudding user response:

Const generics are an area of Rust that is still very much in development and in places it is just not as far as constexpr and the like are in C . This is one of them.

There is an implementation of const generic expressions (i.e. expressions that can be evaluated at compile time, that rely on generic parameters), but this is still incomplete, unstable, and available only in nightly versions of Rust. See the tracking issue https://github.com/rust-lang/rust/issues/76560 for more details.

Here is your example patched up to work with what is currently implemented:

#![feature(generic_const_exprs)]
// We still need this feature and the nightly compiler, because this is still
// in the works and the implementation is incomplete!

fn main() {
    // I changed your array initializers, because you were using the type
    // where a value should have been.
    // The way you wrote them is how you write the type signature for these arrays.
    // I've added the type signature here, but that wasn't necessarily
    // and merely for illustrative purposes. The compiler can infer it here.
    let test_arr: [f64; 10] = [0_f64; 10];
    do_something(test_arr);
}

// The where is still required to restrict this function to values of C where
// C * 3 is a valid size for an array. This might change in the future.
fn do_something<const C: usize>(_array: [f64; C])
where
    [f64; C * 3]: Sized,
{
    // Here you can now just use the generic parameter in an expression.
    // In other places you may have to surround such an expression by curly braces
    // for the sake of syntactical unambiguity.
    let triple_size_array = [0_f64; C * 3];
    println!("{}", triple_size_array.len());
}

And here is a link to a Rust playground with this code.

CodePudding user response:

It seems that an alternative way to address the problem is to extract the generic const into a local const, i.e.

fn foo<const C: usize>()
{
    const A: usize = C;
    // Do something with A
}
  • Related