Последние несколько недель я тратил время на изучение языка программного обеспечения Rust, в основном как средство повышения производительности приложения Elixir, над которым я работал, - но это уже другая история.

Rust заинтриговал меня тем, что 1) он недавно был признан самым любимым языком программного обеспечения ¹, и 2) язык имеет уникальный подход к управлению памятью с использованием таких понятий, как владение и заимствование . Такой подход, по-видимому, позволяет приложениям Rust работать со скоростью выполнения, аналогичной C / C ++, не вызывая страха и страданий, связанных с необходимостью вручную управлять памятью или сборщиком мусора!

По правде говоря, это великолепие не дается бесплатно². Если вы новичок в этом языке и хотите узнать больше, вы можете найти фантастическое введение здесь.

В этой статье я исследую, как элегантно обработать коллекцию типов Rust Option и Result.

Варианты (быть или не быть)

Вкратце, тип Option может быть либо чем-то, либо ничем. Например, значение Some(10) определенно является чем-то: целым числом, заключенным в Some, тогда как None - это много ничего.

В приведенном ниже примере показан массив Option, которые содержат значения u32 или None. Мы хотим развернуть данные из Options.

В этом примере data инициализируется как массив Options. Строка 3 преобразует массив в итератор, который передается функции filter_map вместе с закрытием. Это закрытие обрабатывает каждый из элементов данных по очереди, как ссылки, поэтому необходимо разыменовать входную переменную x, используя звездочку, то есть *x , чтобы получить ее значение.

Следует иметь в виду, что значения filter_map развертывания Option, то есть данные, содержащиеся в some оболочках, извлекаются, а все значения None отбрасываются.

Наконец, функция, collect нетерпеливо оценивает преобразованные данные, которые до этого момента не обрабатывались. Пример вывода выглядит так:

[1, 2, 4, 6]

Option типы полезны, когда вам нужно иметь дело с ситуациями, которые могут привести к ошибке, но по какой-либо причине не важно позже вспоминать, почему что-то пошло не так. Когда это важно, вам нужен тип Result.

Следующий…

Результаты (все в порядке?)

Подобно типу Option, есть тип Result; это может содержать что-то или ошибку. В то время как тип Option использует либо Some, чтобы обернуть успешные результаты, либо None, тип Result использует Ok , чтобы обернуть успешные результаты, или Err, чтобы обернуть информацию об ошибке для ситуаций, когда дела пошли плохо, например Ok(3.14159) и Err("This Bad Thing Happened").

Между прочим, в других функциональных языках, таких как Haskell и F #, тип Result известен как тип Either, поскольку содержащиеся в нем значения могут быть одним из двух значений: Left и Right³ .

В приведенном ниже примере показан массив из шести Result значений⁴.

Подобно предыдущему примеру Option, функцию filter_map можно использовать для извлечения данных из коллекции Result.

Чтобы получить успешные результаты, Ok обернутые значения преобразуются в Some обернутые значения с помощью функции ok. Точно так же информацию об ошибке можно получить, преобразовав Err обернутые значения в Some значения с помощью функции err. Наконец, как мы видели ранее, функция filter_map разворачивает значения Some и отбрасывает все None значения, создавая следующий результат:

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

Далее практический пример!

Анализ текста

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

В приведенном ниже примере исходные данные представляют собой массив целочисленных строк⁵.

Как мы видели ранее, данные преобразуются в итератор, который передается в функцию filter_map вместе с закрытием. В этом случае замыкание анализирует каждый элемент массива от &str до Option<u32>.

Во-первых, функция parse возвращает тип Result - таким образом, сбор данных преобразуется в:

[Ok(1), Ok(2), Err(ParseIntError { kind: InvalidDigit })]

Далее в нашем примере нас интересуют только успешные случаи, поэтому мы можем применить функцию ok для преобразования данных в:

[Some(1), Some(2), None]

И, как мы видели ранее, функция filter_map разворачивает Option значений, поэтому конечный результат:

[1, 2]

Готово!

Вывод

В этом посте мы рассмотрели типы Option и Result, когда они используются, а также то, как развернуть значения Option и Результат коллекций с использованием функций filter_map, ok и err.

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

Живи долго и процветай.

Сноски

[1] Эликсир занял 7-е место. Я был подавлен!
[2] Первые недели, как правило, уходит на борьбу с компилятором. Grrr!
[3] Как правило, ошибки будут более описательными, чем это!
[4] К счастью, термины Rust более описательны.
[5] Или, точнее, массив из & ул.