- PVSM.RU - https://www.pvsm.ru -

Rust на примерах. Часть 2

Это вторая часть из цикла статей по переводу книги «Rust by Example». Первую часть можно прочитать здесь [1].

Продолжим?

Содержание

  1. Выражения [2]
  2. Операторы ветвления [3]
  3. Петли [4]
  4. Цикл while [5]
  5. Цикл for и функция range [6]
  6. Функции [7]

1. Выражения

В Rust почти все фигурные скобки являются выражением, это значит, что они могут вернуть какой-то результат. Такое поведение не всегда нужно, чтобы ничего не возвращать добавьте ; в конец.

Выражения в блоке могут использоваться в качестве r-values [8] значений, а последнее будет назначено как l-value [8].
* Что такое Rvalue и Lvalue читайте здесь [9].

Но, если последнее выражение в блоке будет точкой с запятой, результат будет равен пустому кортежу: ().

fn main() {
    let x = 5u;

    let y = {
        let x_squared = x * x;
        let x_cube = x_squared * x;

        // `y` будет этим выражением
        x_cube + x_squared + x
    };

    let z = {
        // Если в конце стоит точка с запятой, то выражение не
        // присваивается, вместо него переменная `z` будет содержать `()`
        2 * x;
    };

    println!("x is {}", x);
    println!("y is {}", y);
    println!("z is {}", z);
}

2. Операторы ветвления

Ветвление if-else является C-подобным. В отличие от C, логическое условие не должно быть заключено в круглые скобки, а каждому условию необходимы фигурные скобки.

if-else так же является выражением; и, из-за типобезопасности Rust, все ветви должны возвращать значение одного типа.

fn main() {
    let n = 5i;

    if n < 0 {
        print!("{} is negative", n);
    } else if n > 0 {
        print!("{} is positive", n);
    } else {
        print!("{} is zero", n);
    }

    let big_n =
        if n < 10 && n > -10 {
            println!(", and is a small number, increase ten-fold");

            // Это выражение возвращает `int`
            10 * n
        } else {
            println!(", and is a big number, reduce by two");

            // Это выражение должно возвращать `int`
            n / 2
            // ^ Попробуйте поставить точку с запятой
        };

    println!("{} -> {}", n, big_n);
}

3. Петли

Ключевое слово loop в Rust создает бесконечный цикл (петлю).

Оператор break позволяет выйти из петли в любое время, а continue пропускает оставшуюся часть итерации и начинает выполнение заново.

fn main() {
    let mut count = 0u;

    println!("Let's count until infinity!");

    // Бесконечная петля
    loop {
        count += 1;

        if count == 3 {
            println!("three");

            // Пропустим оставшуюся часть этой итерации
            continue;
        }

        println!("{}", count);

        if count == 5 {
            println!("OK, that's enough");

            // Выход из этой петли
            break;
        }
    }
}

3.1 Вложенность и ярлыки

Петли можно делать вложенными. В таких случаях они должны содержать какой-то ярлык 'label, а операторы break/continue писаться с этим ярлыком.

fn main() {
    'outer: loop {
        println!("Entered the outer loop");

        'inner: loop {
            println!("Entered the inner loop");

            // Выход из внутренней петли
            //break;

            // Выход из внешней петли
            break 'outer;
        }

        println!("This point will never be reached");
    }

    println!("Exited the outer loop");
}

4. Цикл while

Тело цикла будет выполняться пока условие в while не будет истинно.

Давайте напишем fizzbuzz используя цикл while.

fn main() {
    // Переменная для счетчика
    let mut n = 1u;

    // Итерируем пока `n` меньше 101
    while n < 101 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }

        // Увеличиваем счетчик
        n += 1;
    }
}

5. Цикл for и функция range

Конструкцию for in можно использовать для перебора Iterator и генератора ленивых значений (подробнее позже). Функция range это один из наиболее распространенных итераторов. range(a, b) будет выдавать значения от a до b-1 изменяя шаг на единицу.

Давайте напишем fizzbuzz используя for вместо while.

fn main() {
    // `n` будет принимать значения: 1, 2, ..., 100 в каждой итерации
    for n in range(1u, 101) {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }
    }
}

6. Функции

Функции объявляются при помощи ключевого слова fn. Аргументы аннотируются типами, как и переменные; и, если функция возвращает значение, возвращаемый тип должен быть указан после стрелки ->.

Последнее выражение в теле функции будет использовано как возвращаемое значение или можно использовать оператор return для раннего возврата значения из функции, даже из внутреннего цикла или условного оператора.

Перепишем fizzbuzz используя функции!

// Функция, которая возвращает булево значение
fn is_divisible_by(lhs: uint, rhs: uint) -> bool {
    // Некорректный входной параметр, сразу выходим из функции
    if rhs == 0 {
        return false;
    }

    // Это выражение, так что ключевое слово `return` тут не нужно
    lhs % rhs == 0
}

// Функции, которые не возвращают значение, на самом деле возвращают тип `()`
fn fizzbuzz(n: uint) -> () {
    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: uint) {
    for n in range(1, n + 1) {
        fizzbuzz(n);
    }
}

fn main() {
    fizzbuzz_to(100);
}

6.1 Неиспользуемые функции

Компилятор обеспечивает dead_code lint [10], чтобы предупреждать о неиспользованных функциях. Можно добавить атрибут #[allow(dead_code)], чтобы отключить уведомление.

fn used_function() {}

// `#[allow(dead_code)]` это атрибут, который отключает предупреждение `dead_code`
#[allow(dead_code)]
fn unused_function() {}

fn noisy_unused_function() {}
// ИСПРАВЬТЕ ^ Добавьте атрибут, чтобы отключить предупреждение

fn main() {
    used_function();
}

Обратите внимание, что в реальных программах, вы должны устранить «мертвый код». В этих примерах мы его используем для демонстрации.

Заключение

Присоединяйтесь к google-группе: Rust по-русски [11] для получения дополнительной информации по этому языку.
Можно помочь с переводом на Github: github.com/eg0r/rust-by-example [12]

Все замечания, ошибки или неточности отправляйте мне в почту.

Автор: seweb

Источник [13]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/primery-koda/67693

Ссылки в тексте:

[1] здесь: http://habrahabr.ru/post/232829/

[2] Выражения: #expression

[3] Операторы ветвления: #ifelse

[4] Петли: #loop

[5] Цикл while: #while

[6] Цикл for и функция range: #for

[7] Функции: #functions

[8] r-values: https://en.wikipedia.org/wiki/Value_%28computer_science%29#lrvalue

[9] здесь: http://msdn.microsoft.com/ru-ru/library/f90831hc.aspx

[10] lint: https://en.wikipedia.org/wiki/Lint_%28software%29

[11] Rust по-русски: https://groups.google.com/forum/#!forum/rust-russian

[12] github.com/eg0r/rust-by-example: https://github.com/eg0r/rust-by-example

[13] Источник: http://habrahabr.ru/post/233621/