Подтвердить что ты не робот

Некоторые и нет, каковы они?

При программировании некоторых небольших упражнений для начинающих, пытающихся привыкнуть к 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?

4b9b3361

Ответ 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.