Как найти значение result

Раздел: Как стать программистом /
Секреты программирования /

Все способы изучить Python

Все способы изучить 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 при вводе некорректных данных:

enum Result and OK and Err in Rust

Тип Result в Rust

Определение

Тип 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 . Если ResultErr :

  • 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 или возвращает предоставленное значение по умолчанию, если ResultErr
  • 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 самого себя.

Понравилась статья? Поделить с друзьями:
  • Как найти угол между биссектрисами острых углов
  • Word как найти статистику
  • Как найти владельца сбербанк карты по карте
  • Как в одноклассниках найти игру зомби
  • Как составить акт осмотра счетчика