Pull to refresh

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

Reading time 4 min
Views 14K
Original author: Jorge Aparicio
Это вторая часть из цикла статей по переводу книги «Rust by Example». Первую часть можно прочитать здесь.

Продолжим?

Содержание


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

1. Выражения


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

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

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

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, чтобы предупреждать о неиспользованных функциях. Можно добавить атрибут #[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 по-русски для получения дополнительной информации по этому языку.
Можно помочь с переводом на Github: github.com/eg0r/rust-by-example

Все замечания, ошибки или неточности отправляйте мне в почту.
Tags:
Hubs:
+24
Comments 19
Comments Comments 19

Articles