Why does array declaration need a length if the initial value is given?

I'm a beginner with rust and trying to understand some of the logic behind the design. One question I have:

Why does an array declaration with type need a length? If no type is given the compiler infers it from the initial value, but if a type is given a length is required. That is,

let a0 = [1, 2, 3]]; compiles an array of isize
let a1:[u8;3] = [1, 2, 3]; compiles an array of u8 but the given size needs to match the array
let a3:[u8] = [1, 2, 3]; does not compile, it needs the length. But if the length in the declaration does not match the length of the initial value it is an error.
let a3:[u8;_]; does not work either.

I'm initializing a fairly long array of integers. If I add or remove values I need to adjust the size. It seems to me if the initial value is given and the values can be interpreted as the requested type that should be sufficient. Is there a reason I'm not seeing that this is not done?

You can use integer postfixes to specify type other than default integer i32:

let a1 = [1u8, 2, 3];

Is basically the same as

let a1: [u8; 3] = [1, 2, 3];

Thanks, that makes my code maintenance easier, but I'm still curious if there is a reason the compiler does not accept the third option

  • Also, it doesn't seem to work for me:

**error: missing type for const item
--> src/main.rs:81:16
|
81 | const PIECEDATA = [12u16, 0x00f0, 1, 0x2222, 0, // data for BAR: length 5
| ^ help: provide a type for the constant: : [u16; 27]

**

That’s because [T] is a DST called “slice”, not an array. DSTs cannot be stored on the stack, only the heap. You can store a reference to a slice (usually called slice too):

let a2: &[u8] = &[1, 2, 3];
1 Like
let a3: [u8; _] = [1, 2, 3];

FWIW, this one arguably "should" work, it's just not currently implemented.

3 Likes

This is false; in your own example above, the DST being referred to by a2 is stack-allocated, it is not on the heap.

In my example, I’m basically storing an SST and than treating a reference to an SST as a reference to a DST by applying some metadata. To store the DST itself, you need to use something like a Box or an Rc, don’t you?

UPD: I forgot that types are just an abstraction and on practice everything is just a buffer, so my explanation is probably wrong.

No. Conceptually, the DST is the slice itself, i.e., whatever is pointed by that reference. It doesn't matter what type it was coerced from. For example, the expression a2[0..2] has no relation to any statically-sized entity in that program; it's a dynamically-sized view into whatever happens to back it in memory.

It's not like you can create a "true" DST using Box by your own definition, either. In order to create a Box<DST>, you have to have a Box<SST> value somewhere that you have to coerce. (Or you can create it by doing unsafe pointer casting, which is what e.g. Vec does, but then there's no actual backing DST either, the slice is created from a raw buffer pointer that has no notion of sizing, either static or dynamic.)

3 Likes

Yeah, I understood I said complete nonsense. I actually meant that to have an owned version of a DST you need to manage it with a smart pointer.

By the way, you actually can store your DST on the stack even without determinating the size at compile time, but it’s a bad practice.

The compiler tells you, that infering the size is unstable. It even gives you the link to the tracking issue.

fn main () {
    let a: [f64; _] = [1., 2.];
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: in expressions, `_` can only be used on the left-hand side of an assignment
 --> src/main.rs:2:18
  |
2 |     let a: [f64; _] = [1., 2.];
  |                  ^ `_` not allowed here

error[E0658]: using `_` for array lengths is unstable
 --> src/main.rs:2:18
  |
2 |     let a: [f64; _] = [1., 2.];
  |                  ^ help: consider specifying the array length: `2`
  |
  = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information

For more information about this error, try `rustc --explain E0658`.
error: could not compile `playground` due to 2 previous errors

1 Like