Главная страница
Навигация по странице:

  • Управляющие конструкции

  • Обработка нескольких условий с помощью

  • Использование if в let-операторах

  • Листинг 3-2: Присвоение результата выражения if переменной

  • Повторение выполнения кода с помощью циклов

  • Повторение выполнения кода с помощью

  • Возвращение значений из циклов

  • Язык программирования Rust


    Скачать 7.02 Mb.
    НазваниеЯзык программирования Rust
    Дата12.04.2023
    Размер7.02 Mb.
    Формат файлаpdf
    Имя файлаThe Rust Programming Language_ru.pdf
    ТипУчебник
    #1056301
    страница6 из 62
    1   2   3   4   5   6   7   8   9   ...   62
    for more information warning: unnecessary parentheses around assigned value
    -->
    src/main.rs:2:13
    |
    2 | let x = (let y = 6);
    | ^ ^
    |
    = note: `#[warn(unused_parens)]` on by default help: remove these parentheses
    |
    2 - let x = (let y = 6);
    2 + let x = let y = 6;
    |
    For more information about this error, try `rustc --explain E0658`. warning: `functions` (bin "functions") generated 1 warning error: could not compile `functions` due to 2 previous errors; 1 warning emitted
    присваивания возвращает значение присваивания. В таких языках можно писать код x
    = y = 6
    и обе переменные x
    и y
    будут иметь одинаковое значение
    6
    . Но в Rust не так.
    Выражения вычисляют значение и составляют большую часть остального кода, который вы напишете на Rust. Рассмотрим математическую операцию, к примеру
    5 + 6
    , которая является выражением, вычисляющим значение
    11
    . Выражения могут быть частью операторов: в листинге 3-1 6
    в операторе let y = 6;
    является выражением, которое вычисляется в значение
    6
    . Вызов функции - это выражение. Вызов макроса - это выражение. Новый блок области видимости, созданный с помощью фигурных скобок,
    представляет собой выражение, например:
    Имя файла: src/main.rs
    Это выражение:
    является блоком, который в данном случае вычисляется как
    4
    . Это значение затем привязывается к y
    как часть оператора let
    . Обратите внимание, что x + 1
    не имеет точки с запятой в конце, в отличие от большинства строк, которые вы видели до сих пор.
    Выражения не включают точку с запятой в конце. Если добавить точку с запятой в конец выражения, то оно превратится в оператор, и не вернёт значение. Помните об этом,
    когда будете изучать возвращаемые функцией значения и выражения.
    Функции с возвращаемыми значениями
    Функции могут возвращать значения коду, который их вызывает. Мы не называем возвращаемые значения, но мы должны объявить их тип после стрелки (
    ->
    ). В Rust возвращаемое значение функции является синонимом значения конечного выражения в блоке тела функции. Вы можете раньше выйти из функции и вернуть значение,
    используя ключевое слово return и указав значение, но большинство функций неявно возвращают последнее выражение. Вот пример такой функции:
    Имя файла: src/main.rs fn main
    () { let y = { let x =
    3
    ; x +
    1
    }; println!
    (
    "The value of y is: {y}"
    );
    }
    { let x =
    3
    ; x +
    1
    }

    В коде функции five нет вызовов функций, макросов или даже операторов let
    - есть только одно число
    5
    . Это является абсолютно корректной функцией в Rust. Заметьте,
    что возвращаемый тип у данной функции определён как
    -> i32
    . Попробуйте запустить этот код. Вывод будет таким:
    Значение
    5
    в five является возвращаемым функцией значением, поэтому возвращаемый тип - i32
    . Рассмотрим пример более детально. Здесь есть два важных момента: во-первых, строка let x = five();
    показывает использование возвращаемого функцией значения для инициализации переменной. Так как функция five возвращает
    5
    , то эта строка эквивалентна следующей:
    Во-вторых, у функции five нет параметров и определён тип возвращаемого значения,
    но тело функции представляет собой одинокую
    5
    без точки с запятой, потому что это выражение, значение которого мы хотим вернуть.
    Рассмотрим другой пример:
    Имя файла: src/main.rs
    Запуск кода напечатает
    The value of x is: 6
    . Но если поставить точку с запятой в конце строки, содержащей x + 1
    , превратив её из выражения в оператор, мы получим fn five
    () -> i32
    {
    5
    } fn main
    () { let x = five(); println!
    (
    "The value of x is: {x}"
    );
    }
    $
    cargo run
    Compiling functions v0.1.0 (file:///projects/functions)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
    Running `target/debug/functions`
    The value of x is: 5 let x =
    5
    ; fn main
    () { let x = plus_one(
    5
    ); println!
    (
    "The value of x is: {x}"
    );
    } fn plus_one
    (x: i32
    ) -> i32
    { x +
    1
    }
    ошибку.
    Имя файла: src/main.rs
    Компиляция данного кода вызывает следующую ошибку:
    Основное сообщение об ошибке "несовпадение типов" раскрывает ключевую проблему этого кода. Определение функции plus_one сообщает, что будет возвращено i32
    , но операторы не вычисляют значение, что и выражается единичным типом
    ()
    Следовательно, ничего не возвращается, что противоречит определению функции и приводит к ошибке. В этом выводе Rust выдаёт сообщение, которое, возможно, поможет исправить эту проблему: он предлагает удалить точку с запятой для устранения ошибки.
    fn main
    () { let x = plus_one(
    5
    ); println!
    (
    "The value of x is: {x}"
    );
    } fn plus_one
    (x: i32
    ) -> i32
    { x +
    1
    ;
    }
    $
    cargo run
    Compiling functions v0.1.0 (file:///projects/functions) error[E0308]: mismatched types
    -->
    src/main.rs:7:24
    |
    7 | fn plus_one(x: i32) -> i32 {
    | -------- ^^^ expected `i32`, found `()`
    | |
    | implicitly returns `()` as its body has no tail or `return` expression
    8 | x + 1;
    | - help: remove this semicolon
    For more information about this error, try `rustc --explain E0308`. error: could not compile `functions` due to previous error

    Комментарии
    Все хорошие программисты, создавая программный код, стремятся сделать его простым для понимания. Бывают всё же случаи, когда дополнительное описание просто необходимо. В этих случаях программисты пишут заметки (или как их ещё называют,
    комментарии). Комментарии игнорируются компилятором, но для тех кто код читает - это очень важная часть документации.
    Пример простого комментария:
    В Rust комментарии должны начинаться двумя символами
    //
    и простираются до конца строки. Чтобы комментарии поместились на более чем одной строке, необходимо разместить
    //
    на каждой строке, как в примере:
    Комментарии могут быть размещены в конце строки имеющей код:
    Файл: src/main.rs
    Но чаще вы увидите их использование в следующем формате, когда комментарий размещён на отдельной строке над кодом, который комментируется:
    Файл: src/main.rs
    Также в Rust есть другой тип комментариев - документирующие комментарии, которые мы обсудим в разделе "Публикация пакета на Crates.io" Главы 14.
    // Hello, world.
    // So we’re doing something complicated here, long enough that we need
    // multiple lines of comments to do it! Whew! Hopefully, this comment will
    // explain what’s going on.
    fn main
    () { let lucky_number =
    7
    ;
    // I’m feeling lucky today
    } fn main
    () {
    // I’m feeling lucky today let lucky_number =
    7
    ;
    }

    Управляющие конструкции
    Способность запускать некоторый код в зависимости от истинности условия или выполнять некоторый код многократно, пока условие истинно, является базовым элементом большинства языков программирования. Наиболее распространёнными конструкциями, позволяющими управлять потоком выполнения кода в Rust, являются выражения if и циклы.
    Выражения if
    Выражение if позволяет разветвлять код в зависимости от условий. Вы задаёте условие, а затем объявляете: "Если это условие соблюдено, то выполнить этот блок кода.
    Если условие не соблюдается, не выполнять этот блок кода".
    Для изучения выражения if создайте новый проект под названием branches в каталоге
    projects. В файл src/main.rs поместите следующий код:
    Имя файла: src/main.rs
    Все выражения if начинаются с ключевого слова if
    , за которым следует условие. В
    этом случае условие проверяет, имеет ли переменная number значение меньше 5. Если условие истинно, мы помещаем блок исполняемого кода сразу после условия внутри фигурных скобок. Блоки кода, связанные с условиями в выражениях if
    , иногда называются ответвлениями, точно так же, как ответвления в выражениях match
    ,
    которые мы обсуждали в разделе
    «Сравнение догадки с секретным числом»
    Главы 2.
    Опционально можно включить выражение else
    , которое мы используем в данном примере, чтобы предоставить программе альтернативный блок выполнения кода,
    выполняющийся при ложном условии. Если не указать выражение else и условие будет ложным, программа просто пропустит блок if и перейдёт к следующему фрагменту кода.
    Попробуйте запустить этот код. Появится следующий результат:
    fn main
    () { let number =
    3
    ; if number <
    5
    { println!
    (
    "condition was true"
    );
    } else
    { println!
    (
    "condition was false"
    );
    }
    }

    Попробуйте изменить значение number на значение, которое делает условие false и
    посмотрите, что произойдёт:
    Запустите программу снова и посмотрите на вывод:
    Также стоит отметить, что условие в этом коде должно быть логического типа bool
    . Если условие не является bool
    , возникнет ошибка. Например, попробуйте запустить следующий код:
    Имя файла: src/main.rs
    На этот раз условие if вычисляется в значение
    3
    , и Rust бросает ошибку:
    Ошибка говорит, что Rust ожидал тип bool
    , но получил значение целочисленного типа.
    В отличии от других языков вроде Ruby и JavaScript, Rust не будет пытаться автоматически конвертировать нелогические типы в логические. Необходимо явно и всегда использовать if с логическим типом в качестве условия. Если нужно, чтобы блок
    $
    cargo run
    Compiling branches v0.1.0 (file:///projects/branches)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31s
    Running `target/debug/branches` condition was true let number =
    7
    ;
    $
    cargo run
    Compiling branches v0.1.0 (file:///projects/branches)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31s
    Running `target/debug/branches` condition was false fn main
    () { let number =
    3
    ; if number { println!
    (
    "number was three"
    );
    }
    }
    $
    cargo run
    Compiling branches v0.1.0 (file:///projects/branches) error[E0308]: mismatched types
    -->
    src/main.rs:4:8
    |
    4 | if number {
    | ^^^^^^ expected `bool`, found integer
    For more information about this error, try `rustc --explain E0308`. error: could not compile `branches` due to previous error
    кода if запускался только, когда число не равно
    0
    , то, например, мы можем изменить выражение if на следующее:
    Имя файла: src/main.rs
    Будет напечатана следующая строка number was something other than zero
    Обработка нескольких условий с помощью else if
    Можно использовать несколько условий, комбинируя if и else в выражении else if
    Например:
    Имя файла: src/main.rs
    У этой программы есть четыре возможных пути выполнения. После её запуска вы должны увидеть следующий результат:
    Во время выполнения этой программы по очереди проверяется каждое выражение if и
    выполняется первое тело, для которого условие истинно. Заметьте, что хотя 6 делится на
    2, мы не видим ни вывода number is divisible by 2
    , ни текста number is not divisible by 4, 3, or 2
    из блока else
    . Так происходит потому, что Rust выполняет блок только для первого истинного условия, а обнаружив его, даже не проверяет остальные.
    fn main
    () { let number =
    3
    ; if number !=
    0
    { println!
    (
    "number was something other than zero"
    );
    }
    } fn main
    () { let number =
    6
    ; if number %
    4
    ==
    0
    { println!
    (
    "number is divisible by 4"
    );
    } else if number %
    3
    ==
    0
    { println!
    (
    "number is divisible by 3"
    );
    } else if number %
    2
    ==
    0
    { println!
    (
    "number is divisible by 2"
    );
    } else
    { println!
    (
    "number is not divisible by 4, 3, or 2"
    );
    }
    }
    $
    cargo run
    Compiling branches v0.1.0 (file:///projects/branches)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31s
    Running `target/debug/branches` number is divisible by 3

    Использование множества выражений else if приводит к загромождению кода,
    поэтому при наличии более чем одного выражения, возможно, стоит провести рефакторинг кода. В главе 6 описана мощная конструкция ветвления Rust для таких случаев, называемая match
    Использование if в let-операторах
    Поскольку if является выражением, его можно использовать в правой части оператора let для присвоения результата переменной, как в листинге 3-2.
    Имя файла: src/main.rs
    Листинг 3-2: Присвоение результата выражения
    if
    переменной
    Переменная number будет привязана к значению, которое является результатом выражения if
    . Запустим код и посмотрим, что происходит:
    Вспомните, что блоки кода вычисляются последним выражением в них, а числа сами по себе также являются выражениями. В данном случае, значение всего выражения if зависит от того, какой блок выполняется. При этом значения, которые могут быть результатами каждого из ветвей if
    , должны быть одного типа. В Листинге 3-2,
    результатами обеих ветвей if и else являются целочисленный тип i32
    . Если типы не совпадают, как в следующем примере, мы получим ошибку:
    Имя файла: src/main.rs
    При попытке компиляции этого кода, мы получим ошибку. Ветви if и else представляют несовместимые типы значений, и Rust точно указывает, где искать fn main
    () { let condition = true
    ; let number = if condition {
    5
    } else
    {
    6
    }; println!
    (
    "The value of number is: {number}"
    );
    }
    $
    cargo run
    Compiling branches v0.1.0 (file:///projects/branches)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
    Running `target/debug/branches`
    The value of number is: 5 fn main
    () { let condition = true
    ; let number = if condition {
    5
    } else
    {
    "six"
    }; println!
    (
    "The value of number is: {number}"
    );
    }
    проблему в программе:
    Выражение в блоке if вычисляется как целочисленное, а выражение в блоке else вычисляется как строка. Это не сработает, потому что переменные должны иметь один тип, а Rust должен знать во время компиляции, какого типа переменная number
    . Зная тип number
    , компилятор может убедиться, что тип действителен везде, где мы используем number
    . Rust не смог бы этого сделать, если бы тип number определялся только во время выполнения. Компилятор усложнился бы и давал бы меньше гарантий в отношении кода, если бы ему приходилось отслеживать несколько гипотетических типов для любой переменной.
    Повторение выполнения кода с помощью циклов
    Часто бывает полезно выполнить блок кода более одного раза. Для этой задачи Rust предоставляет несколько циклов, которые позволяют выполнить код внутри тела цикла до конца, а затем сразу же вернуться в начало. Для экспериментов с циклами давайте создадим новый проект под названием loops.
    В Rust есть три вида циклов: loop
    , while и for
    . Давайте попробуем каждый из них.
    Повторение выполнения кода с помощью loop
    Ключевое слово loop говорит Rust выполнять блок кода снова и снова до бесконечности или пока не будет явно приказано остановиться.
    В качестве примера, измените код файла src/main.rs в каталоге проекта loops на код ниже:
    Имя файла: src/main.rs
    $
    cargo run
    Compiling branches v0.1.0 (file:///projects/branches) error[E0308]: `if` and `else` have incompatible types
    -->
    src/main.rs:4:44
    |
    4 | let number = if condition { 5 } else { "six" };
    | - ^^^^^ expected integer, found
    `&str`
    | |
    | expected because of this
    For more information about this error, try `rustc --explain E0308`. error: could not compile `branches` due to previous error fn main
    () { loop
    { println!
    (
    "again!"
    );
    }
    }

    Когда запустим эту программу, увидим, как again!
    печатается снова и снова, пока не остановить программу вручную. Большинство терминалов поддерживают комбинацию клавиш ctrl-c для прерывания программы, которая застряла в непрерывном цикле.
    Попробуйте:
    Символ
    ^C
    обозначает место, где было нажато ctrl-c . В зависимости от того, где находился код в цикле в момент получения сигнала прерывания, вы можете увидеть или не увидеть слово again!
    , напечатанное после
    ^C
    К счастью, Rust также предоставляет способ выйти из цикла с помощью кода. Ключевое слово break нужно поместить в цикл, чтобы указать программе, когда следует прекратить выполнение цикла. Напоминаем, мы делали так в игре "Угадайка" в разделе "Выход после правильной догадки"
    Главы 2, чтобы выйти из программы, когда пользователь выиграл игру, угадав правильное число.
    Мы также использовали continue в игре "Угадайка", которая указывает программе в цикле пропустить весь оставшийся код в данной итерации цикла и перейти к следующей итерации.
    Возвращение значений из циклов
    Одно из применений loop
    - это повторение операции, которая может закончиться неудачей, например, проверка успешности выполнения потоком своего задания. Также может понадобиться передать из цикла результат этой операции в остальную часть кода.
    Для этого можно добавить возвращаемое значение после выражения break
    , которое используется для остановки цикла. Это значение будет возвращено из цикла, и его можно будет использовать, как показано здесь:
    $
    cargo run
    Compiling loops v0.1.0 (file:///projects/loops)
    Finished dev [unoptimized + debuginfo] target(s) in 0.29s
    Running `target/debug/loops` again! again! again! again!
    ^Cagain!

    Перед циклом мы объявляем переменную с именем counter и инициализируем её
    значением
    0
    . Затем мы объявляем переменную с именем result для хранения значения, возвращаемого из цикла. На каждой итерации цикла мы добавляем
    1
    к переменной counter
    , а затем проверяем, равен ли счётчик
    10
    . Когда это происходит,
    мы используем ключевое слово break со значением counter * 2
    . После цикла мы ставим точку с запятой для завершения инструкции, присваивающей значение result
    Наконец, мы выводим значение в result
    , равное в данном случае 20.
    1   2   3   4   5   6   7   8   9   ...   62


    написать администратору сайта