Выбрать главу

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);

}

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה