Массив фиксированного размера, обозначаемый [T; N], для типа элемента, T, и неотрицательного постоянного размера времени компиляции, N.

Это то, что вы обнаружите, когда прочитаете первые несколько строк документации о типе array в Rust.

Давайте рассмотрим это по частям.
Для начала у нас есть следующее

Массив фиксированного размера…

Итак, теперь мы знаем, что массив никогда не будет увеличиваться или уменьшаться в памяти. Если вы создадите массив, вмещающий 5 элементов типа bool, он навсегда останется массивом, вмещающим 5 bool.

Продолжаем и находим описание

… обозначается [Т; Н]

[T; N] сообщает нам формат, который следует использовать при объявлении массива.
Но были ли T и N?

… для типа элемента, T

T относится к типу элементов массива. Если бы мы хотели хранить числа в массиве, Tможносослаться на тип i32 в Rust, [i32; N].
Чтобы лучше понять N, нам нужно прочитать следующую часть, которая

… и неотрицательный постоянный размер времени компиляции, N.

N представляет размер нашего массива, и в документации упоминаются два правила, которым должен следовать N.

Первое правило
Nдолжно быть неотрицательным числом.
Давайте не будем подчиняться этому правилу и посмотрим, что произойдет :-)

let array_with_negative_size: [i32; -3];

Это вызывает ошибку компилятора

error[E0600]: cannot apply unary operator `-` to type `usize`

С учетом ошибки мы видим, что компилятор ожидает usize как тип N. Тип usize представляет целое число без знака, поэтому оно никогда не может быть меньше 0.

Второе правило
Nдолжно быть константой времени компиляции. Если какое-либо выражение, используемое для N, нельзя заменить постоянным значением, правило нарушается.

Здесь мы пытаемся использовать параметр n, переданный функции, в качестве значения для N.

fn compile_time_array_size(n: usize) {
  let array_with_positive_size: [i32; n];
}

Это вызывает ошибку компилятора

error[E0435]: attempt to use a non-constant value in a constant

И вот оно.

Идти дальше …

Существуют две синтаксические формы для создания массива:

Список с каждым элементом, например [x, y, z].

Повторяющееся выражение [x; N], который создает массив с N копиями x. Тип x должен быть "Копировать".

Это то, что вы обнаружите, если продолжите читать документацию.
В ней выделены два способа фактического создания массива.

Метододин

Список с каждым элементом, то есть [x, y, z].

let array_of_numbers = [0, 1, 1, 2, 3, 5, 8];

Что мы декларировали в этом случае?

Для начала компилятор может определить, что у нас есть 7 элементов в нашем массиве, и будет использовать это для установки размера (N) массива.

Но как насчет T?
Rust по умолчанию использует i32 для чисел, что означает, что мы только что объявили массив с 7 элементами i32s, [i32; 7].

Что произойдет, если у вас есть литерал, в котором значения любого из элементов превышают возможности i32?

let array_of_numbers = [0, 1, 10_000_000_000];

Компилятор будет жаловаться на

error: literal out of range for `i32`

Из этого мы можем сделать вывод, что Rust не поможет нам автоматически изменить тип на что-то более подходящее, например i64. Для этого нам нужно сделать следующее

let array_of_numbers: [i64; 3] = [0, 1, 10_000_000_000];

Теперь у нас есть массив, содержащий 3 элемента i64.

Конкретные значения в литерале массива могут быть описаны более чем постоянными значениями. Например, вы можете установить значения с помощью выражения.

fn array_littera(s: String) {
  let array = [s.len(), s.len() + 1, s.len() + 2];
}

Способ второй

Повторяющееся выражение [x; N], который создает массив с N копиями x. Тип x должен быть Copy.

Удерживая наше внимание на массивах, мы просто взглянем на часть «должно быть Копировать» и просто поймем, что черта Копировать — это просто то, что позволяет нам копировать значения. . Более важная часть — понять, для чего используется функция копирования.

N по-прежнему представляет размер массива, но теперь у нас есть x, что является «повторяющимся выражением». Другими словами, это возьмет x и будет использовать его в качестве начального значения для всех наших элементов. Теперь мы видим, почему его нужно копировать, значение, которое мы даем x, необходимо повторно скопировать в массив.

В документации используется слово «выражение», мы можем сделать много с выражением в Rust. Это означает, что мы можем гораздо более динамично создавать значение x.

Давайте немного поиграем с этим :-)

fn create_array_with_fn_as_repeatable_expression(string: String) {
  let array = [string.len(); 2];
}

Или… вы могли бы сделать это (вероятно, не должны).

fn create_array_with_repeatable_expression(input: u128) {
  let array_of_number = [{
    let modulus = 10 * input;
    std::time::SystemTime::now()
      .duration_since(std::time::UNIX_EPOCH)
      .map(|d| d.as_millis())
      .map(|n| n % modulus)
      .unwrap_or(10)
   }; 3];
}

Но почему?
Почему полезно знать эти два метода?
Одна из причин заключается в том, что вы не можете работать с массивом, если он не инициализирован.

Это, например, не удастся

let array: [i32; 10];
let length = array.len();

и выдает ошибку компилятора

error[E0381]: borrow of possibly-uninitialized variable: `array`

Таким образом, эти два метода позволяют вам инициализировать массив либо

  • явное задание каждого значения
  • или путем предоставления значения для копирования в каждый элемент массива

Конец.