Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What expressions are allowed as the array length N in [_; N]?

Please consider the following minimal example in Rust:

const FOOBAR: usize = 3;

trait Foo {
    const BAR: usize;
}

struct Fubar();

impl Foo for Fubar {
    const BAR: usize = 3;
}

struct Baz<T>(T);

trait Qux {
    fn print_bar();
}

impl<T: Foo> Qux for Baz<T> {
    fn print_bar() {
        println!("bar: {}", T::BAR);   // works
        println!("{:?}", [T::BAR; 3]); // works
        println!("{:?}", [1; FOOBAR]); // works
        println!("{:?}", [1; T::BAR]); // this gives an error
    }
}

fn main() {
    Baz::<Fubar>::print_bar();
}

The compiler gives the following error:

error[E0599]: no associated item named `BAR` found for type `T` in the current scope
  --> src/main.rs:24:30
   |
24 |         println!("{:?}", [1; T::BAR]); // this gives an error
   |                              ^^^^^^ associated item not found in `T`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `BAR`, perhaps you need to implement it:
           candidate #1: `Foo`

Whatever the answer to my question, this is not a particularly good error message because it suggests that T does implement Foo despite the latter being a trait bound. Only after burning a lot of time did it occur to me that in fact T::BAR is a perfectly valid expression in other contexts, just not as a length parameter to an array.

What are the rules that govern what kind of expressions can go there? Because arrays are Sized, I completely understand that the length are to be known at compile time. Coming from C++ myself, I would expect some restriction akin to constexpr but I have not come across that in the documentation where it just says

A fixed-size array, denoted [T; N], for the element type, T, and the non-negative compile-time constant size, N.

like image 643
Jonas Greitemann Avatar asked Mar 24 '18 18:03

Jonas Greitemann


People also ask

What is the length in an array?

Summary. The length property of an array is an unsigned, 32-bit integer that is always numerically greater than the highest index of the array. The length returns the number of elements that a dense array has.

What property tells you the length of a JavaScript array?

The length property of an object which is an instance of type Array sets or returns the number of elements in that array. The value is an unsigned, 32-bit integer that is always numerically greater than the highest index in the array.


1 Answers

As of Rust 1.24.1, the array length basically needs to either be a numeric literal or a "regular" constant that is a usize. There's a small amount of constant evaluation that exists today, but it's more-or-less limited to basic math.

a perfectly valid expression in other contexts, just not as a length parameter to an array

Array lengths don't support generic parameters. (#43408)

this is not a particularly good error message

Error message should be improved for associated consts in array lengths (#44168)

I would expect some restriction akin to constexpr

This is essentially the restriction, the problem is that what is allowed to be used in a const is highly restricted at the moment. Notably, these aren't allowed:

  • functions (except to construct enums or structs)
  • loops
  • multiple statements / blocks

Work on good constant / compile-time evaluation is still ongoing. There are a large amount of RFCs, issues, and PRs improving this. A sample:

  • Const fn tracking issue (RFC 911)
  • Allow locals and destructuring in const fn (RFC 2341)
  • Allow if and match in constants (RFC 2342)
like image 191
Shepmaster Avatar answered Nov 15 '22 07:11

Shepmaster