fn give_princess(gift: &str) {
// Принцесса ненавидит змей, поэтому нам нужно остановиться, если она не одобрит!
if gift == "змея" { panic!("AAAaaaaa!!!!"); }
println!("Я люблю тебя, {}!!!!!", gift);
}
fn main() {
give_princess("плюшевый мишка");
give_princess("змея");
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Optionиunwrap
В последнем примере мы показали, что мы по собственному желанию можем вызвать сбой программы. Мы сказали нашей программе вызвать panic, если принцессе подарят несоответствующий подарок - змею. Но что если принцесса ожидает подарок, но не получает его? Этот случай тоже плохой, так что и он должен быть обработан!
Мы можем проверить пустую строку ("") так же, как мы сделали это со змеёй. Поскольку мы используем Rust, давайте укажем компилятору случаи, когда подарка нет.
Перечисление (enum) из стандартной библиотеки (std), называющееся Option, используется, когда значение может отсутствовать. Оно проявляется как одна из двух опций (options):
• Some(T): элемент типа T найден
• None: элемент не найден
Эти случаи могут быть явно обработаны через match или неявно с unwrap. Неявная обработка либо вернёт внутренний элемент, либо вызовет panic.
Обратите внимание, что можно вручную настроить сообщение отображаемое при вызове panic с помощью expect, но unwrap в противном случае оставляет нам менее понятный вывод, чем явная обработка. В следующем примере явная обработка при желании даёт более контролируемый результат, сохраняя при этом возможности panic.
// Простолюдин видел всё это, и может справиться с любым подарком хорошо.
// Все подарки обрабатываются с помощью `match`.
fn give_commoner(gift: Option<&str>) {
// Укажите порядок действий для каждого случая.
match gift {
Some("змея") => println!("Фу! Я унесу эту змею обратно в лес."),
Some(inner) => println!("{}? Как хороший.", inner),
None => println!("Нет подарка? Ну что же."),
}
}
// Наша защищённая принцесса будет паниковать при виде змей.
// Все подарки обрабатываются неявно через `unwrap`.
fn give_princess(gift: Option<&str>) {
// `unwrap` вызовет `panic` когда получит `None`.
let inside = gift.unwrap();
if inside == "змея" { panic!("AAAaaaaa!!!!"); }
println!("Я люблю {}!!!!!", inside);
}
fn main() {
let food = Some("капуста");
let snake = Some("змея");
let void = None;
give_commoner(food);
give_commoner(snake);
give_commoner(void);
let bird = Some("малиновка");
let nothing = None;
give_princess(bird);
give_princess(nothing);
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
РазворачиваниеOptionс?
Вы можете развернуть Option с использованием match, но часто проще бывает использовать оператор?. Если x - Option, то выражениеx? вернёт значение переменной, если x - Some, в противном же случае оно завершит выполнение текущей функции и вернёт None.
fn next_birthday(current_age: Option) -> Option {
// Если `current_age` == `None`, то возвращаем `None`.
// Если `current_age` == `Some`, то содержащееся в ней `u8` будет присвоено переменной `next_age`
let next_age: u8 = current_age?;
Some(format!("В следующем году мне будет {}", next_age))
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Чтобы ваш код был более читаемым, вы можете составить цепочку из нескольких ?.
struct Person {
job: Option,
}
#[derive(Clone, Copy)]
struct Job {
phone_number: Option,
}
#[derive(Clone, Copy)]
struct PhoneNumber {
area_code: Option,
number: u32,
}
impl Person {
// Получим из рабочего номера телефона код региона, если он существует.
fn work_phone_area_code(&self) -> Option {
// Мы можем не использовать оператор `?` и тогда здесь будет много вложенных операторов `match`.
// С ним кода будет больше. Попробуйте использовать в этом коде `match` и посмотрите,
// какой вариант проще.
self.job?.phone_number?.area_code
}
}
fn main() {
let p = Person {
job: Some(Job {
phone_number: Some(PhoneNumber {
area_code: Some(61),
number: 439222222,
}),
}),
};
assert_eq!(p.work_phone_area_code(), Some(61));
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX