Некоторые и нет, каковы они?
При программировании некоторых небольших упражнений для начинающих, пытающихся привыкнуть к Rust, я натолкнулся на некоторые результаты, которые я не понимаю, используя Vec::get
. Здесь код:
fn main() {
let command = [('G', 'H'), ('H', '5')];
for i in 0..3 {
print!(" {} ", i);
println!("{:?}", command.get(i));
}
}
вывод
0 Some(('G', 'H'))
1 Some(('H', '5'))
2 None
Я раньше занимался в Haskell, и я имею в виду, что смотрел сайт-учебник в течение 10 минут и возвращался на С++, но я помню, что читал что-то о Some
и None
для Haskell. Я был удивлен, увидев это здесь, в Русте. Может ли кто-нибудь объяснить, почему .get()
возвращает Some
или None
?
Ответы
Ответ 1
Подпись get
(для срезов, а не Vec
, так как вы используете массив/срез) есть
fn get(&self, index: usize) -> Option<&T>
То есть, он возвращает Option
, который является перечислением, определенным как
pub enum Option<T> {
None,
Some(T),
}
None
и Some
являются вариантами перечисления, то есть значение с типом Option<T>
может быть либо None
, либо оно может быть Some
, содержащим значение типа T
.
Это то же самое, что и основной тип data Maybe a = Nothing | Just a
в Haskell; оба представляют собой необязательное значение, оно либо там (Some
/Just
), либо оно не (None
/Nothing
).
Эти типы часто используются для представления отказа, когда есть только одна возможность, почему что-то не удалось, например, .get
использует Option
, чтобы предоставить доступ к массиву с контролируемым типом: он возвращает None
(т.е. no данные), когда индекс выходит за пределы, в противном случае он возвращает Some
, содержащий запрошенный указатель.
Ответ 2
command
не является вектором (тип Vec<T>
), это массив фиксированного размера (тип [(char, char); 2]
в вашем случае), а массивы автоматически заимствуются на срезы (представления в массивы), поэтому вы можете используйте все методы, определенные на срезах, включая get
:
Возвращает элемент среза в указанном индексе или None
, если индекс не соответствует границам.
Поведение довольно очевидно: если данный индекс действителен, он возвращает Some
с элементом под этим индексом, в противном случае он возвращает None
.
Существует еще один способ доступа к элементам в срезе - оператор индексирования, который должен быть вам знаком:
let nums = [1, 2, 3];
let x = nums[1];
Он возвращает элемент среза напрямую, но он не сможет выполнить текущую задачу, если индекс выходит за рамки:
fn main() {
let x = [1, 2];
for i in 0..3 {
println!("{}", x[i]);
}
}
Эта программа не работает:
% ./main2
1
2
task '<main>' failed at 'index out of bounds: the len is 2 but the index is 2', main2.rs:4
get()
необходим метод удобства; это избавит вас от проверки заранее, если данный индекс действителен.
Если вы не знаете, что действительно есть Some
и None
и почему они необходимы вообще, вы должны прочитать официальный учебник, он объясняет это, потому что это очень простая концепция.
Ответ 3
Подумайте о Some
и None
как о каноническом "безопасном" способе работы над тем фактом, что язык Rust не поддерживает "безопасное" использование указателей NULL
. Поскольку длина вашего Vec
равна 3, и вы указали только две пары, третья пара эффективно NULL
; вместо возврата NULL
он возвращает None
.
Rust обеспечивает гарантии безопасности, заставляя нас во время компиляции с помощью Some
/None
всегда иметь дело с возможностью возврата None
.