Раздел: Как стать программистом /
Секреты программирования /
|
Все способы изучить Python
Каждый раз, изучая какую-то новую науку, мы задаёмся вопросом — где взять обучающие материалы. Конечно, сегодня нам помогает в этом Интернет. Но иногда на поиски уходит очень много времени, а нужного результата мы не получаем… Собрал для вас кучу полезных ссылок для изучения Python. не благодарите ))) |
Слово Result в Паскале в используется для возврата результата из
функции.
Как известно, любая функция возвращает какой-то результат. Обычно в Паскале это делается так:
function MyFunc(x : integer) : integer; begin MyFunc := x * x; end;
То есть где-то в теле функции (обычно в конце, после выполнения всего кода функции)
мы пишем имя функции, используя его как идентификатор переменной, и присваиваем ей какое-то значение.
Таким образом в нашем примере функция MyFunc вернёт результат — квадрат числа Х. Если в программе мы вызовем нашу функцию, например, так:
WriteLn(MyFunc(10));
то на экран будет выведено число 100.
Впрочем, всё это вы уже должны знать.
А вот эту фишку многие новички не знают:
function MyFunc(x : integer) : integer; begin Result := x * x; end;
Обратите внимание, что здесь вместо имени функции мы пишем слово Result.
И функция будет работать точно также. То есть возвращать результат, как это и положено функции.
Прекрасно. Но остаётся вопрос — зачем это надо?
Вот это то и есть основная тема данной статьи. Здесь я покажу вам две причины, почему и когда лучше использовать именно слово Result, а не имя функции для возврата результата.
Причина первая
Довольно часто в практике программирования приходится создавать похожие функции. При этом обычно полностью копируется исходная функция. А затем немного дорабатывается и переименовывается.
Если вы используете такой формат:
function MyFunc(x : integer) : integer;
begin
MyFunc := x * x;
end;
То вам придётся переименовывать функцию не менее чем в двух местах. Если же вы используете слово Result, то вам надо будет переименовать функцию только в одном месте — в заголовке.
Мелочь?
Да. Но, как говорится, дьявол кроется в мелочах. И профессионал отличается от любителя именно отношением к мелочам.
Кроме того, при копировании функции, как правило, мы переименовываем её в заголовке, но часто забываем сделать это там, где функция возвращает результат.
Компилятор, конечно, в этом случае выдаёт ошибку. Но перед этим вы тратите время на компиляцию. И время течёт буквально сквозь пальцы…
Например, в то время, как я пишу эту статью, я занимаюсь разработкой довольно сложной программы, на что у меня уже ушло 250 часов. И ещё уйдёт примерно столько же.
А теперь представьте, что с помощью разных фишек вам удастся сэкономить хотя бы одну минуту из часа и помножьте это на общее количество часов. Цифра будет немаленькой. А ведь это ваше время!
Причина вторая
Вторая причина перекликается с первой. Связана она тоже с возможной необходимостью переименования функции (это может потребоваться по разным причинам).
Представьте, что у вас есть такая функция:
function MyFunc2(x : integer) : integer; begin case x of 1 : MyFunc2 := x * 100; 2 : MyFunc2 := x * 200; 3 : MyFunc2 := x * 300; end; end;
И представьте, что вы решили её переименовать.
В этом случае вам придётся переименовать все идентификаторы
в селекторах конструкции case.
В нашем примере их три. Но ведь может быть и 100 и более.
А если бы вы использовали слово Result, то вам опять же надо было бы переименовать только заголовок.
Конечно, в редакторе исходного кода есть такие вещи как поиск и замена, но ведь и их использование тоже отнимает время.
В общем, надеюсь, я убедил вас в полезности использования слова Result в Паскале.
Применяйте эту замечательную возможность и, поверьте, это избавит вас от множества
неприятностей и позволит сэкономить время на разработку программ.
|
Директивы компилятора Как это ни странно, но даже многие опытные программисты не используют директивы компилятора, считая их чем-то ненужным и бесполезным. А между тем, директивы компилятора — это очень классная штука. Если их умело применять в своих программах, то можно существенно сократить время на разработку и уменьшить количество рутинных операций. Подробнее… |
Последнее обновление: 04.05.2021
Многие ошибки не требуют завершения программы. Такие ошибки можно обработать и продолжить выполнение программы. Для этой цели в Rust
предназначен тип Result. Данный тип представляет enum или перечисление, которое определяет две константы:
Ok и Err.
enum Result<T, E> { Ok(T), Err(E), }
Это перечисление типизировано двумя параметрами типа: T и E. T представляет тип
значения, который будет возвращаться в случае успешного выполнения. А параметр E представляет тип ошибки,
которая будет возвращаться через константу Err
в случае возникновения ошибки.
Рассмотрим, как использовать перечисление Result. Допустим, у нас есть функция, которая создает объект некоторой структуры:
struct Person{ name: String, age:u8} fn create_person(username: &str, userage: u8) -> Result<Person, String>{ if userage < 110{ let new_person = Person{name: String::from(username), age: userage }; Result::Ok(new_person) } else { Result::Err(String::from("Некорректный возраст. Возраст должен быть меньше 110")) } }
Итак, у нас есть структура Person, которая содержит два поля: name — имя пользователя и age — возраст пользователя. И также определена функция
create_person()
, которая принимает данные для имени и возраста пользователя и по ним создает объект Person. Однако данная
функция возвращает не просто объект Person, а объект перечисления Result<Person, String>.
А это значит, что функция должна возвращать либо константу Ok, в которую передается значение Person, либо константу Err, в которую должно передаваться значение String.
Логика функции проста: если возраст корректен (в данном случае меньше 110), то объект Person создается. Если возраст некорретен, то нет смысла создавать
объект Person.
Если действия завершились успешно, то возвращается константа Ok, которая содержит созданный объект Person.
Result::Ok(new_person)
Если действия по созданию объекта Person завершились неудачно, то возвращается константа Err,
которая содержит информацию об ошибке в виде объекта String — некоторое сообщение об ошибке.
Result::Err(String::from("Некорректный возраст. Возраст должен быть меньше 110"))
Теперь применим это в программе:
fn main() { // пример корректного ввода - функция возвращает константу Result::Ok let tom_result = create_person("Tom", 36); match tom_result{ Ok(tom) => println!("Name: {} Age: {}", tom.name, tom.age), Err(err_message) => println!("{}", err_message) } // пример некорректного ввода - функция возвращает константу Result::Err let bob_result = create_person("Bob", 136); match bob_result{ Ok(bob) => println!("Name: {} Age: {}", bob.name, bob.age), Err(err_message) => println!("{}", err_message) } println!("Конец программы..."); } struct Person{ name: String, age:u8} fn create_person(username: &str, userage: u8) -> Result<Person, String>{ if userage < 110{ let new_person = Person{name: String::from(username), age: userage }; Result::Ok(new_person) } else { Result::Err(String::from("Некорректный возраст. Возраст должен быть меньше 110")) } }
Вначале передаем корректные данные:
let tom_result = create_person("Tom", 36);
Чтобы узнать, что собой представляет полученный результат tom_result
, используем конструкцию match
:
match tom_result{ Ok(tom) => println!("Name: {} Age: {}", tom.name, tom.age), Err(err_message) => println!("{}", err_message) }
Если создание объекта Person завершилось успешно, то мы получим константу Ok. В данном случае из константы в переменную tom
получаем
возвращенный объект Person и выводим его данные на консоль:
Ok(tom) => println!("Name: {} Age: {}", tom.name, tom.age),
Если создание Person завершилось неудачно, то выполняется выражение
Err(err_message) => println!("{}", err_message)
которое помещает в переменную err_message
объект String с сообщением об ошибке и выводит его на консоль.
Для второго вызова функции логика аналогична. В итоге мы получим следующий консольный вывод:
Name: Tom Age:36 Некорректный возраст. Возраст должен быть меньше 110 Конец программы...
Вызов макроса panic
Как именно обрабатывать ошибку, зависит от разных условий. Например, в примере выше предполагалось, что отсутствие объекта Person некритично.
Однако вероятны ситуации, когда ошибка может повлиять на возможность дальнейшего выполнения программы. Вполне возможно, что
если объект Person не создан, то дальше нет смысла продолжать работу программы. И в этом случае ее можно завершить макросом panic!:
fn main() { let tom_result = create_person("Tom", 36); let tom = match tom_result{ Ok(person) => person, Err(err_message) => panic!("Возникла проблема: {}", err_message) }; println!("Name: {} Age: {}", tom.name, tom.age); }
Здесь, используя синтаксис паттернов, получаем из результата tom_result значение Person. Если результат представляет константу Ok()
,
то передаем из нее в переменную person объект Person и возвращаем его:
Ok(person) => person
В итоге это значение перейдет в переменную tom
. И далее мы сможем, например, вывести полученные данные на консоль или как-то иным образом использовать
полученный объект Person.
Если результат представляет константу Err
, то вызываем макрос panic!
, в котором выводит сообщение на консоль. Соответственно
при выполнении этого макроса программа завершает свое выполнение.
Пример выполнения макроса panic при вводе некорректных данных:
Определение
Тип Result
— это обобщенное перечисление из стандартной библиотеки Rust и результат вычисления: успешный с вариантом Ok
и неуспешный с Err
.
Тип Result
определяется так:
enum Result<T, E> {
Ok(T),
Err(E),
}
The T
и E
— это типы успешных и неуспешных результатов соответственно. Result<T, E>
применяется при вычислении, в котором возвращается значение типа T
при успехе и ошибка типа E
при неуспехе.
Пример использования
Вот Result
для оборачивания результата функции, которая может выполниться неуспешно:
fn parse_int(s: &str) -> Result<i32, std::num::ParseIntError> {
s.parse::<i32>().map_err(|e| e.into())
}fn main() {
let result = parse_int("5");
match result {
Ok(n) => println!("Parsed integer: {}", n),
Err(e) => println!("Error parsing integer: {}", e),
}
}
Если попытка спарсить число из строки успешна, в функции parse_int
возвращается вариант Ok
с полученным числом, если неуспешна — вариант Err
с ParseIntError
.
Обработка значений Result
Для обработки значения Result
применяется сопоставление с образцом. В примере выше для обработки вариантов Ok
и Err
использовано выражение match
.
Кроме того, чтобы извлечь значение из варианта Ok
, применяется метод unwrap
. Но он «запаникует», если значение — вариант Err
:
let result = parse_int("5");
let n = result.unwrap(); // «запаникует», если результат — вариант Err
println!("Parsed integer: {}", n);
Из-за возможности паники unwrap()
не рекомендуется использовать в производственном коде.
Другой способ обработки значения Result
— методы map
и map_err
: значение внутри варианта Ok
и Err
преобразуется применением к нему функции.
В функции divide
, например, делятся 2 числа и возвращается Result
— показатель успешного деления:
fn divide(x: i32, y: i32) -> Result<i32, DivisionError> {
if y == 0 {
return Err(DivisionError::DivideByZero);
}
Ok(x / y)
}
map()
и map_err()
Чтобы преобразовать успешный результат деления в другой тип, например в число с плавающей точкой, применяется метод map
:
let result = divide(10, 2);
let f: Result<f32, DivisionError> = result.map(|n| n as f32);
Чтобы преобразовать значение ошибки в другой тип, применяется метод map_err
:
let result = divide(10, 0);
let f: Result<i32, &str> = result.map_err(|e| match e {
DivisionError::DivideByZero => "Divide by zero",
DivisionError::Negative => "Cannot divide by negative number",
});
Другие методы обработки результата
Кроме методов map
и map_err
, у типа Result
имеются и другие способы манипулирования значениями и их обработки:
fn add_one(x: i32) -> Result<i32, &'static str> {
if x > 100 {
return Err("Number too large");
}
Ok(x + 1)
}fn add_two(x: i32) -> Result<i32, &'static str> {
if x > 50 {
return Err("Number too large");
}
Ok(x + 2)
}fn add_three(x: i32) -> Result<i32, &'static str> {
if x > 30 {
return Err("Number too large");
}
Ok(x + 3)
}// С использованием and_then
let result = add_one(5).and_then(|x| add_two(x)).and_then(|x| add_three(x));
assert_eq!(result, Ok(11));// С использованием or_else
let result = add_one(105).or_else(|e| add_two(5)).or_else(|e| add_three(5));
assert_eq!(result, Ok(7));// С использованием unwrap_or
let result = add_one(105).unwrap_or(100);
assert_eq!(result, 100);// С использованием unwrap_or_else
let result = add_one(105).unwrap_or_else(|e| -1);
assert_eq!(result, -1);
В этих примерах показаны 3 функции, каждая из которых выполняет операцию и возвращает значение Result
.
Методом and_then
они связываются, и, если все вычисления успешные, возвращается конечный результат операций. Если какое-либо вычисление неуспешно, сразу возвращается вариант Err
.
Метод or_else
аналогичен, но применяется к варианту Err
, а не Ok
. Здесь также указывается резервное вычисление, если исходное неуспешно.
В методе unwrap_or
возвращается значение внутри варианта Ok
или значение по умолчанию, если Result
— вариант Err
. Метод пригодится, когда в случае ошибки нужно указать значение по умолчанию, а не обрабатывать ее явно.
Метод unwrap_or_else
аналогичный, но, чтобы получить значение по умолчанию, в качестве аргумента принимается замыкание, применяемое к значению ошибки внутри варианта Err
. Метод пригодится, когда нужно вычислить значение по умолчанию на основе значения ошибки.
Читайте также:
- Почему разработчики JavaScript используют инструменты на Rust
- Реализация Redux на Rust
- Actix или Rocket? Сравнение двух мощных платформ для веб-приложений на Rust
Читайте нас в Telegram, VK и Дзен
Перевод статьи Pascal Zwikirsch: Rust: Result Type Explained
In Pascal, a function is a subroutine that returns a value. The value that is returned by the function is called the function result.
There are three ways to set the result of a function, depending upon the compiler and the version of Pascal:
- Using the
Result
variable - Using the name of the function
- Using the
Exit
call
Note that different versions and compilers of Pascal might not support some of the above-stated methods.
Using the Result
variable
Result
is a special variable that is automatically declared and accessible inside a function. To return a value from any function, we can assign that value to this variable.
The value of the Result
variable at the end of the function is returned from the function.
For example:
Обработка ошибок с типом Result
.
Result<T, E>
— это тип, используемый для возврата и распространения ошибок. Это перечисление с вариантами Ok(T)
, представляющее успех и содержащее значение, и Err(E)
, представляющее ошибку и содержащее значение ошибки.
enum Result<T, E> { Ok(T), Err(E), }
Функции возвращают Result
всякий раз, когда ошибки ожидаются и могут быть исправлены. В std
обрешетке, Result
наиболее заметно используются для ввода / вывода .
Простую функцию, возвращающую Result
можно определить и использовать так:
#[derive(Debug)] enum Version { Version1, Version2 } fn parse_version(header: &[u8]) -> Result<Version, &'static str> { match header.get(0) { None => Err("invalid header length"), Some(&1) => Ok(Version::Version1), Some(&2) => Ok(Version::Version2), Some(_) => Err("invalid version"), } } let version = parse_version(&[1, 2, 3, 4]); match version { Ok(v) => println!("working with version: {v:?}"), Err(e) => println!("error parsing header: {e:?}"), }
Сопоставление с образцом в Result
s является ясным и простым для простых случаев, но Result
поставляется с некоторыми удобными методами, которые делают работу с ним более лаконичной.
let good_result: Result<i32, i32> = Ok(10); let bad_result: Result<i32, i32> = Err(10); assert!(good_result.is_ok() && !good_result.is_err()); assert!(bad_result.is_err() && !bad_result.is_ok()); let good_result: Result<i32, i32> = good_result.map(|i| i + 1); let bad_result: Result<i32, i32> = bad_result.map(|i| i - 1); let good_result: Result<bool, i32> = good_result.and_then(|i| Ok(i == 11)); let bad_result: Result<i32, i32> = bad_result.or_else(|i| Ok(i + 20)); let final_awesome_result = good_result.unwrap();
Результаты должны быть использованы
Общая проблема с использованием возвращаемых значений для индикации ошибок заключается в том, что возвращаемое значение легко игнорировать, что не позволяет обработать ошибку. Result
аннотируется атрибутом #[must_use]
, который заставит компилятор выдать предупреждение, если значение Result будет проигнорировано. Это делает Result
особенно полезным для функций, которые могут столкнуться с ошибками, но в противном случае не возвращают полезного значения.
Рассмотрим метод write_all
, определенный для типов ввода-вывода свойством Write
:
use std::io; trait Write { fn write_all(&mut self, bytes: &[u8]) -> Result<(), io::Error>; }
Примечание. Фактическое определение Write
использует io::Result
, который является просто синонимом Result<T, io::Error>
.
Этот метод не создает значение, но запись может завершиться ошибкой. Крайне важно обрабатывать случай ошибки, а не писать что-то вроде этого:
use std::fs::File; use std::io::prelude::*; let mut file = File::create("valuable_data.txt").unwrap(); file.write_all(b"important message");
Если вы делаете запись , что в Русте, компилятор выдаст вам предупреждение (по умолчанию, контролируемое unused_must_use
пух).
Вместо этого, если вы не хотите обрабатывать ошибку, вы можете просто заявить об успехе с помощью expect
. Это вызовет панику, если запись завершится ошибкой, предоставляя незначительно полезное сообщение, указывающее, почему:
use std::fs::File; use std::io::prelude::*; let mut file = File::create("valuable_data.txt").unwrap(); file.write_all(b"important message").expect("failed to write message");
Ты также можешь просто утверждать успех:
assert!(file.write_all(b"important message").is_ok());
Или распространить ошибку вверх по стеку вызовов с помощью ?
:
fn write_message() -> io::Result<()> { let mut file = File::create("valuable_data.txt")?; file.write_all(b"important message")?; Ok(()) }
Оператор вопросительного знака ?
При написании кода, вызывающего множество функций, возвращающих тип Result
, обработка ошибок может быть утомительной. Оператор вопросительного знака ?
, скрывает некоторые шаблоны распространения ошибок вверх по стеку вызовов.
Он заменяет это:
use std::fs::File; use std::io::prelude::*; use std::io; struct Info { name: String, age: i32, rating: i32, } fn write_info(info: &Info) -> io::Result<()> { let mut file = match File::create("my_best_friends.txt") { Err(e) => return Err(e), Ok(f) => f, }; if let Err(e) = file.write_all(format!("name: {}n", info.name).as_bytes()) { return Err(e) } if let Err(e) = file.write_all(format!("age: {}n", info.age).as_bytes()) { return Err(e) } if let Err(e) = file.write_all(format!("rating: {}n", info.rating).as_bytes()) { return Err(e) } Ok(()) }
With this:
use std::fs::File; use std::io::prelude::*; use std::io; struct Info { name: String, age: i32, rating: i32, } fn write_info(info: &Info) -> io::Result<()> { let mut file = File::create("my_best_friends.txt")?; file.write_all(format!("name: {}n", info.name).as_bytes())?; file.write_all(format!("age: {}n", info.age).as_bytes())?; file.write_all(format!("rating: {}n", info.rating).as_bytes())?; Ok(()) }
Это намного приятнее!
Завершить выражение с помощью ?
приведет к результату развернутого успеха ( Ok
), если только результат не будет Err
, и в этом случае Err
возвращается рано из включающей функции.
?
может использоваться только в функциях, возвращающих Result
, из-за раннего возврата Err
, который он предоставляет.
Method overview
Помимо работы с сопоставлением с образцом, Result
предоставляет широкий спектр различных методов.
Запрос варианта
В is_ok
и is_err
методы возвращают true
, если Result
является Ok
или Err
, соответственно.
Адаптеры для работы со ссылками
-
as_ref
преобразует&Result<T, E>
вResult<&T, &E>
-
as_mut
преобразует из&mut Result<T, E>
вResult<&mut T, &mut E>
-
as_deref
преобразует&Result<T, E>
вResult<&T::Target, &E>
-
as_deref_mut
преобразует&mut Result<T, E>
вResult<&mut T::Target, &mut E>
Эти методы извлекают содержащееся значение в Result<T, E>
если это вариант Ok
. Если Result
— Err
:
-
expect
паники с предоставленным настраиваемым сообщением -
unwrap
панику с помощью общего сообщения -
unwrap_or
возвращает предоставленное значение по умолчанию -
unwrap_or_default
возвращает значение по умолчанию для типаT
(который должен реализовыватьсвойствоDefault
) -
unwrap_or_else
возвращает результат оценки предоставленной функции
Методы panicking expect
и unwrap
требуют, чтобы E
реализовал Debug
.
Эти методы извлекают содержащееся значение в Result<T, E>
если это вариант Err
. Им требуется T
для реализации трейта Debug
. Если Result
в Ok
:
-
expect_err
паникует с предоставленным настраиваемым сообщением -
unwrap_err
паникует с общим сообщением
Преобразование содержащихся ценностей
Эти методы преобразуют Result
в Option
:
-
err
преобразуетResult<T, E>
вOption<E>
, преобразуяErr(e)
вSome(e)
иOk(v)
вNone
-
ok
преобразуетResult<T, E>
вOption<T>
, сопоставляяOk(v)
сSome(v)
иErr(e)
сNone
-
transpose
переводитResult
Option
вOption
Result
__
Этот метод преобразует содержащееся значение варианта Ok
:
-
map
преобразуетResult<T, E>
вResult<U, E>
, применяя предоставленную функцию к содержащемуся значениюOk
и оставляязначенияErr
неизменными
Этот метод преобразует содержащееся значение варианта Err
:
-
map_err
преобразуетResult<T, E>
вResult<T, F>
, применяя предоставленную функцию к содержащемуся значениюErr
и оставляязначенияOk
без изменений
Эти методы преобразуют Result<T, E>
в значение, возможно, другого типа U
:
-
map_or
применяет предоставленную функцию к содержащемуся значениюOk
или возвращает предоставленное значение по умолчанию, еслиResult
—Err
-
map_or_else
применяет предоставленную функцию к содержащемуся значениюOk
или применяет предоставленную резервную функцию по умолчанию к содержащемуся значениюErr
Boolean operators
Эти методы обрабатывают Result
как логическое значение, где Ok
действует как true
а Err
действует как false
. Есть две категории этих методов: те, которые принимают Result
в качестве входных данных, и те, которые принимают функцию в качестве входных данных (для ленивого вычисления).
В and
и or
способах сделать еще один Result
в качестве входных данных, и производят Result
в качестве вывода. Метод and
может создавать значение Result<U, E>
имеющее внутренний тип U
, отличный от Result<T, E>
. or
метод может произвести Result<T, F>
значение , имеющее другой тип ошибки F
, чем Result<T, E>
.
method | self | input | output |
---|---|---|---|
and |
Err(e) |
(ignored) | Err(e) |
and |
Ok(x) |
Err(d) |
Err(d) |
and |
Ok(x) |
Ok(y) |
Ok(y) |
or |
Err(e) |
Err(d) |
Err(d) |
or |
Err(e) |
Ok(y) |
Ok(y) |
or |
Ok(x) |
(ignored) | Ok(x) |
and_then
и or_else
методы принимают функцию в качестве входных данных, и только оценить функцию , когда необходимо произвести новое значение. Метод and_then
может создавать значение Result<U, E>
имеющее внутренний тип U
, отличный от Result<T, E>
. or_else
метод может произвести Result<T, F>
значение , имеющее другой тип ошибки F
, чем Result<T, E>
.
method | self | function input | function result | output |
---|---|---|---|---|
and_then |
Err(e) |
(not provided) | (not evaluated) | Err(e) |
and_then |
Ok(x) |
x |
Err(d) |
Err(d) |
and_then |
Ok(x) |
x |
Ok(y) |
Ok(y) |
or_else |
Err(e) |
e |
Err(d) |
Err(d) |
or_else |
Err(e) |
e |
Ok(y) |
Ok(y) |
or_else |
Ok(x) |
(not provided) | (not evaluated) | Ok(x) |
Comparison operators
Если и T
, и E
реализуют PartialOrd
, тогда Result<T, E>
получит свою реализацию PartialOrd
. В этом порядке Ok
сравнивается как меньшее, чем любое Err
, в то время как два Ok
или два Err
сравниваются, поскольку их содержащиеся значения были бы в T
или E
соответственно. Если T
и E
оба также реализуют Ord
, то также и Result<T, E>
.
assert!(Ok(1) < Err(0)); let x: Result<i32, ()> = Ok(0); let y = Ok(1); assert!(x < y); let x: Result<(), i32> = Err(0); let y = Err(1); assert!(x < y);
Итерация по Result
Результат может быть повторен Result
Это может быть полезно, если вам нужен условно пустой итератор. Итератор либо выдаст одно значение (когда Result
равен Ok
), либо не выдаст никаких значений (когда Result
равен Err
). Например, into_iter
действует как Once once(v)
, если Result
является Ok(v)
, и как empty()
, если Result
является Err
.
Итераторы Result<T, E>
бывают трех типов:
-
into_iter
используетResult
и создает содержащееся в нем значение -
iter
создает неизменяемую ссылку типа&T
на содержащееся значение -
iter_mut
создает изменяемую ссылку типа&mut T
на содержащееся значение
См. « Итерация по Option
где приведены примеры того, как это может быть полезно.
Возможно, вы захотите использовать цепочку итераторов для выполнения нескольких экземпляров операции, которая может завершиться ошибкой, но хотите игнорировать ошибки, продолжая обрабатывать успешные результаты. В этом примере мы используем итеративный характер Result
для выбора только значений Ok
с помощью flatten
.
let mut results = vec![]; let mut errs = vec![]; let nums: Vec<_> = ["17", "not a number", "99", "-27", "768"] .into_iter() .map(u8::from_str) .inspect(|x| results.push(x.clone())) .inspect(|x| errs.extend(x.clone().err())) .flatten() .collect(); assert_eq!(errs.len(), 3); assert_eq!(nums, [17, 99]); println!("results {results:?}"); println!("errs {errs:?}"); println!("nums {nums:?}");
Собирая в Result
Result
реализует FromIterator
, который позволяет собирать итератор позначениям Result
в Result
коллекции каждого содержащегося значения исходных Result
или Err
, если какой-либо из элементов был Err
.
let v = [Ok(2), Ok(4), Err("err!"), Ok(8)]; let res: Result<Vec<_>, &str> = v.into_iter().collect(); assert_eq!(res, Err("err!")); let v = [Ok(2), Ok(4), Ok(8)]; let res: Result<Vec<_>, &str> = v.into_iter().collect(); assert_eq!(res, Ok(vec![2, 4, 8]));
Result
также реализует Product
и Sum
, позволяя итератору по Result
предоставлятьметоды product
и sum
.
let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")]; let res: Result<i32, &str> = v.into_iter().sum(); assert_eq!(res, Err("error!")); let v = [Ok(1), Ok(2), Ok(21)]; let res: Result<i32, &str> = v.into_iter().product(); assert_eq!(res, Ok(42));
Structs
Итератор по значению в варианте Ok
Result
.
Итератор по ссылке на вариант Ok
Result
.
Итератор по изменяемой ссылке на вариант Ok
Result
.
Enums
Result
— это тип, который представляет либо успех ( Ok
), либо неудачу ( Err
).
Rust
1.65
-
impl<T, E> Результат<&T, E>
Maps Result<&T, скопировав содержимое части Ok.
-
impl<T, E> Residual<T> for Result<Infallible, E>
Тип «возврата» этой мета-функции.
-
Struct std::result::IntoIter
Итератор по значению в Ok варианте Result.
-
impl <T> FusedIterator для IntoIter <T>
Получает TypeId самого себя.