Последние несколько недель я тратил время на изучение языка программного обеспечения Rust, в основном как средство повышения производительности приложения Elixir, над которым я работал, - но это уже другая история.
Rust заинтриговал меня тем, что 1) он недавно был признан самым любимым языком программного обеспечения ¹, и 2) язык имеет уникальный подход к управлению памятью с использованием таких понятий, как владение и заимствование . Такой подход, по-видимому, позволяет приложениям Rust работать со скоростью выполнения, аналогичной C / C ++, не вызывая страха и страданий, связанных с необходимостью вручную управлять памятью или сборщиком мусора!
По правде говоря, это великолепие не дается бесплатно². Если вы новичок в этом языке и хотите узнать больше, вы можете найти фантастическое введение здесь.
В этой статье я исследую, как элегантно обработать коллекцию типов Rust Option и Result.
Варианты (быть или не быть)
Вкратце, тип Option может быть либо чем-то, либо ничем. Например, значение Some(10)
определенно является чем-то: целым числом, заключенным в Some
, тогда как None
- это много ничего.
В приведенном ниже примере показан массив Option
, которые содержат значения u32
или None
. Мы хотим развернуть данные из Option
s.
В этом примере data
инициализируется как массив Option
s. Строка 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] Или, точнее, массив из & ул.