enum, Option, и RFC
Так же, как иif let, while let может сделать неудобный match более терпимым. Рассмотрим следующий пример, в котором мы увеличиваем значение i:
#![allow(unused)]
fn main() {
// Создадим переменную `optional` с типом `Option<i32>`
let mut optional = Some(0);
// Неоднократно повторим наш тест.
loop {
match optional {
// Если `optional` деструктурируется, выполним следующий блок.
Some(i) => {
if i > 9 {
println!("Больше 9, уходим отсюда!");
optional = None;
} else {
println!("`i` равен `{:?}`. Попробуем еще раз.", i);
optional = Some(i + 1);
}
// ^ Требует 3 уровня вложенности!
},
// Выходим из цикла в случаи ошибки деструктуризации:
_ => { break; }
// ^ Зачем это нужно? Должен быть способ сделать это лучше!
}
}
}
Использование while let делает этот пример немного приятнее:
fn main() {
// Создадим переменную `optional` с типом `Option<i32>`
let mut optional = Some(0);
// Это можно прочитать так: "Пока `let` деструктурирует `optional` в
// `Some(i)`, выполняем блок (`{}`). В противном случае `break`.
while let Some(i) = optional {
if i > 9 {
println!("Больше 9, уходим отсюда!");
optional = None;
} else {
println!("`i` равен `{:?}`. Попробуем ещё раз.", i);
optional = Some(i + 1);
}
// ^ Меньше смещаемся вправо, к тому же
// нет необходимости обрабатывать ошибки.
}
// ^ К `if let` можно добавить дополнительный блок `else`/`else if`
// `while let` подобного нет.
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
enum, Option, and the RFC
Функции объявляются с помощью ключевого слова fn. Их аргументы имеют явно заданный тип, как у переменных, и, если функция возвращает значение, возвращаемый тип должен быть указан после стрелки ->.
Последнее выражение в функции будет использовано как возвращаемое значение. Так же можно использовать оператор return, чтобы вернуть значение из функции раньше, даже из цикла или оператора if.
Давайте перепишем FizzBuzz используя функции!
// В отличие от С/С++, нет никаких ограничений касаемо порядка определений функций
fn main() {
// Можно использовать функцию здесь, а определить где-нибудь потом
fizzbuzz_to(100);
}
// Функция, возвращающая логическое значение
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
// Граничный случай, ранний возврат
if rhs == 0 {
return false;
}
// Это - выражение, ключевое слово `return` здесь не требуется
lhs % rhs == 0
}
// Функция, которая «не возвращает» значение, на самом деле возвращает единичный тип `()`
fn fizzbuzz(n: u32) -> () {
if is_divisible_by(n, 15) {
println!("fizzbuzz");
} else if is_divisible_by(n, 3) {
println!("fizz");
} else if is_divisible_by(n, 5) {
println!("buzz");
} else {
println!("{}", n);
}
}
// Когда функция возвращает `()`, возвращаемый тип можно не указывать
fn fizzbuzz_to(n: u32) {
for n in 1..n + 1 {
fizzbuzz(n);
}
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה