Продолжаю изучать Rust и вот решил попробовать в нём массивы.
Массивы в Rust неитерабельные, тоесть нельзя написать for item in array {...}
. Вместо этого придётся написать либо for item in &array {...}
либо for item in array.iter() {...}
либо for item in array.to_vec() {...}
либо что-то другое похожее, что создаёт из массива объект итерабельного типа. Ну или использовать цикл, который бежит по индексам for i in 0..array.len() { let n = array[i]; ...}
. По моему это недостаток Rust. Для примера в Java for-each неявно разворачивается в одну из двух версий: с использованием индекса или с использованием итератора - в зависимости от того массив ли это или Iterable. Rust умеет делать лишь второй вариант, хотя это такой же синтаксический сахар, как и for-each в Java.
Так же, на сколько я понял, массив в Rust является не объектом, как в Java, а просто куском памяти с обвесами из макросов, как в C/C++. Таким образом функция не может получить, в качестве параметра, массив, длина которого неизвестна во время компиляции. Следующие три варианта функции не скомпилируются с тремя разными сообщениями об ошибке:
fn print_array1(array: [i32]) {
//
}
fn print_array2(array: [i32; n], n: i32) {
//
}
fn print_array3(n: i32, array: [i32; n]) {
//
}
Варианты вроде
fn print_array(array: [i32; 27]) {...}
работать будут, но практической пользы не имеют. Значит придётся передавать не массив, а созданный из него итерабельный объект. Но это приводит к накладным расходам и с точки зрения системного программирования выглядит не очень хорошо. Может быть это ограничение снято в unsafe?Ну хорошо, пусть речь идёт не о системном, а о прикладном программировании. Предположим, что я хочу пройтись по всем элементам двумерного массива, например, чтобы распечатать его в виде таблицы. В этом случае удобнее сразу пользоваться не массивом, а скажем слайсом (срезом), более похожим на массив в Java. В итоге у меня получился следующий код:
fn main() {
let desk: &[&[i32]] = &[&[1, 2, 3, 4], &[5, 6, 7, 8], &[9, 10, 11, 12], &[13, 14, 15, 16]];
print_desk(desk)
}
fn print_desk(desk: &[&[i32]]) {
for line in desk {
for cell in *line {
print!("{:02} ", cell)
}
println!()
}
}
Здесь у меня возникла проблема во внутреннем цикле. Я полагал, что типом переменной
line
является &[i32]
, но оказалост, что он &&[i32]
. Поэтому во внутреннем цикле пришлось бежать не по line
, а по *line
. Другими вариантами были line.iter()
или line.to_vec()
. Почему здесь такой неконсистентный синтаксис? Так же, почему в сообщении об ошибке предлагается использовать более накладный line.iter()
а не *line
?