Массивы

Последнее обновление: 08.05.2024

Массивы представляют набор элементов, при этом все элементы набора должны представлять один и тот же тип данных.

В Rust массив можно определять различными способами. Простейшее формальное объявление массива:

let название_массива: [тип_данных; размер];

После названия массива через двоеточие, как и в общем случае, указывается тип данных. Но в случае с массивом тип данных массива указывается в квадратных скобках и состоит из двух компонент: сначала указывается тип данных элементов массива, а потом через точку с запятой размер массива, то есть число его элементов.

Например, объявление массива, который имеет 7 элементов типа i32:

let numbers: [i32; 7];

Фактически выражение [i32; 7] выступает в качестве типа массива. То есть фактически мы определили переменную numbers и указали ее тип - [i32; 7] - массив из 7 элементов типа i32. Но такая переменная еще неинициализирована. Поэтому использовать мы ее не можем.

Для инициализации переменной массива необходимо ей присвоить набор значений. Простейшее определение с инициализацией:

let переменная_массива: [тип_данных; размер] = [элемент1, элемент2, ... элементN];

В качестве значения в квадратных скобках через запятую перечисляются элементы массива. Например:

let numbers: [i32; 7] = [1, 2, 3, 5, 8, 13, 21];

В данном случае массив numbers имеет 7 элементов: 1, 2, 3, 5, 8, 13, 21.

Как и в случае с обычной переменной можно сначала объявить переменную, а затем инициализировать ее:

let numbers: [i32; 7];
numbers	= [1, 2, 3, 5, 8, 13, 21];

Также если массив инициализируется при его определении, то можно не указывать тип массива:

let numbers = [1, 2, 3, 5, 8, 13, 21];

В этом случае Rust сам выведет тип - [i32; 7]

Rust предоставляет удобный способ для вывода всего массива на консоль:

fn main(){
     
    let numbers = [1, 2, 3, 4, 5, 6, 7, 8];
    println!("{:?}", numbers); // [1, 2, 3, 4, 5, 6, 7, 8]
}

Обращение к элементам массива

Для обращения к элементам массива используется их числовой индекс:

название_массива[индекс_элемента]

Каждый элемент массива имеет числовой индекс. Индексация начинается с нуля. То есть первый элемент массива будет иметь индекс 0, второй элемент - индекс 1 и так далее.

Например, выведем на консоль первый и третий элементы массива:

fn main()
{
	let users = ["Tom", "Bob", "Sam"];
	println!("{}", users[0]);	//	Tom
	println!("{}", users[2]);	//	Sam
}

Подобным образом можно не только получить, но и изменять элемент массива. Однако, если мы собираемся изменять элементы массива, то он должен определен с модификатором mut:

fn main(){

	let mut users = ["Tom", "Bob", "Sam"];
	// выводим второй элемент массива
	println!("{}", users[1]);	//	Bob
	// изменяем второй элемент массива
	users[1] = "Bill";
	// снова выводим второй элемент массива
	println!("{}", users[1]);	//	Bill
}

Стоит учитывать, что мы не можем обратиться к несуществующему элементу. Например, выше в примере в массиве есть всего три элемента. Соответственно индексом последнего элемента является число 2. Поэтому к элементам с индексами 3, 4 и больше мы обратиться не можем, так как их просто не существует. Например, в следующем случае при попытке обращения к несуществующему элементу мы столкнемся с ошибкой на этапе компиляции:

fn main(){

	let mut users = ["Tom", "Bob", "Sam"];
	
	users[6] = "Bill";	// !Ошибка - элемента с индексом 6 в массиве users нет
}

Также следует учитывать, что массивы в Rust имеют фиксированный размер. После их определения мы не можем ни уменьшить, ни увеличить их размер.

Длина массива

С помощью метода len() можно получить длину массива:

fn main(){

	let users = ["Tom", "Bob", "Sam"];
	
	println!("count: {}", users.len()); // count: 3
}

Перебор массива

Для перебра массива применяется цикл for:

fn main(){

	let users = ["Tom", "Bob", "Sam"];
	for user in users {
		print!("{} ", user);
	}
	
	println!(); // переходим на следующую строку в консоли
	
	let numbers = [1, 2, 3, 5, 8, 13, 21];
	for n in numbers{
		print!("{} ", n);
	}
}

Консольный вывод программы:

Tom Bob Sam
1 2 3 5 8 13 21

Используя длину массива, можно перебрать массив с учетом индексов элементов:

fn main(){

	let users = ["Tom", "Bob", "Sam"];
	for i in 0..users.len(){
        println!("{}", users[i]);
    }
}

В данном случае создается диапазон чисел от 0 до users.len(), каждое из которых помещается в переменную i, выполняющую роль индекса.

Заполнение массива значениями по умолчанию

Массивы также имеют еще одну форму определения:

let название_массива: [тип_данных; размер] = [значение_по умолчанию; размер];

В качестве значения в квадратных скобках сначала указывается значение по умолчанию, которым заполняется массив. А затем через точку с запятой количество элементов массива, которые должны принять это значение.

let numbers: [i32; 5] = [2; 5];

В данном случае каждый из пяти элементов массива numbers будет иметь значение "2".

Также можно сократь определение массива и не указывать тип:

fn main(){

	let numbers = [2; 5];
	for n in numbers{
		print!("{} ", n);		// 2 2 2 2 2
	}
}

Методы массивов

Для массивов доступен ряд методов. Все они включены в модуль std::array. Рассмотрим применение наиболее используемого метода - sort(), который сортирует массив:

fn main(){

	let mut users = ["Tom", "Bob", "Sam"];
    users.sort();
	println!("users: {:?} ", users);

	
	let mut numbers = [1, 8, 5, 21, 13, 2, 3];
	numbers.sort();
	println!("numbers: {:?} ", numbers);
}

По умолчанию массивы сортируются по возрастанию (строки сортируются в лексикографическом порядке), причем подобные массивы должны быть изменяемыми. Консольный вывод:

users: ["Bob", "Sam", "Tom"] 
numbers: [1, 2, 3, 5, 8, 13, 21] 

Копирование массивов

Массивы Rust реализуют трейт Copy, если их типы элементов также реализуют Copy. Это означает, что для подобных массивов копирование происходит неявно во время присваиваний или вызовов функций:

fn main(){

	let original = [1, 2, 3];
    let copied = original;
	println!("copied: {:?} ", copied);  // copied: [1, 2, 3]
}

Однако если тип элемента массива не реализует трейт Copy, то подобный массив нельзя скопировать напрямую. Вместо этого нужно использовать метод to_owned() для клонирования массива. Например:

fn main(){

	let original = ["Tom", "Bob", "Sam"];
    let copied = original.to_owned();
	println!("copied: {:?} ", copied);  // copied: ["Tom", "Bob", "Sam"];
}

Стоит отметить, что клонирование массива предполагает создание нового массива с идентичными элементами, что может оказаться затратно с точки зрения памяти и производительности.

Многомерные массивы

Массивы могут быть одномерными и многомерными. Одномерные массивы можно представить в виде строки или столбца, в которых элементы массивы расположены в ряд. Ранее рассмотренные массивы все были одномерными, например:

let numbers = [1, 2, 3, 4, 5, 6];

Массив numbers является одномерным, его можно представить следующим образом:

123456

Многомерные массивы же представляют массивы, элементы которых сами являются массивами, то есть массивы содержат другие массивы. Рассмотрим частый случай многомерного массива - двухмерный массив:

let numbers = [
    [1, 2, 3],
    [4, 5, 6]
];

Здесь массив numbers содержит два элемента, которые, в свою очередь, также являются массивами. Причем каждый такой вложенный массив имеет три элемента. Типом такого массива является [[i32; 3]; 2]. То есть мы можем записать следующим образом:

let numbers: [[i32; 3]; 2] = [
    [1, 2, 3],
    [4, 5, 6]
];

В данном случае тип массива [[i32; 3]; 2] указывает, что массив имеет два элемента типа [i32; 3]. Тип же [i32; 3] представляет массив из 3 чисел типа i32

Такой массив еще можно представить в виде таблицы, где каждый вложенный массив представляет строку

123
456

Обращение к элементам

Для обращения к элементам подобного массива также используются индексы:

fn main(){
     
    let numbers: [[i32; 3]; 2] = [
        [1, 2, 3],
        [4, 5, 6]
    ];
    let array0: [i32;3] = numbers[0]; // первый вложенный массив
    println!("{:?}", array0);    // [1, 2, 3]

    let array1: [i32;3] = numbers[1]; // первый вложенный массив
    println!("{:?}", array1);    // [4, 5, 6]
}

Здесь выражение numbers[0] указывает, что мы обращаемся к первому элементу массива numbers (элементу с индексом 0), то есть к подмассиву [1, 2, 3]. Поскольку каждый элемент сам является массивом, то для его вывода используем макрос println!("{:?}", array0)

Для получения элемента во вложенном массиве, можно использовать два индекса:

fn main(){
     
    let numbers: [[i32; 3]; 2] = [
        [1, 2, 3],
        [4, 5, 6]
    ];
    let n1: i32 = numbers[0][1]; // второй элемент первого вложенного массива
    println!("{}", n1);     // 2
}

В выражении numbers[0][1] первый индекс [0] указывает, что мы получаем первый вложенный массив, а второй индекс [1] - что мы получаем второе число в этом вложенном массиве. То есть в итоге это будет число 2.

Перебор многомерных массивов

Для перебора многомерного массива можно использовать все те же способы. Например:

fn main(){
     
    let numbers: [[i32; 3]; 2] = [
        [1, 2, 3],
        [4, 5, 6]
    ];
    for array in numbers{
        println!("{:?}", array); 
    }
}

Здесь мы пробегаемся по всем элементам массива numbers. Консольный вывод:

[1, 2, 3]
[4, 5, 6]

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

fn main(){
     
    let numbers: [[i32; 3]; 2] = [
        [1, 2, 3],
        [4, 5, 6]
    ];
    for array in numbers{       // получаем вложенные массивы
        for number in array{    // получаем числа во вложенных массивах
            print!("{} ", number);
        }
        println!(); 
    }
}

Консольный вывод:

1  2  3
4  5  6
Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850