Подтвердить что ты не робот

В чем разница между циклом и while?

Учебник Rust, и теперь book утверждают, что существует разница между while true и loop, но что это не очень важно понимать на этом этапе.

Если вам нужен бесконечный цикл, у вас может возникнуть соблазн написать следующее:

while true {

Однако у Rust есть выделенное ключевое слово, цикл, чтобы обработать этот случай:

loop {

Анализ контроля потока ржавчины рассматривает эту конструкцию иначе, чем истину, поскольку мы знаем, что она всегда будет циклической. Детали того, что это означает, не очень важны для понимания на данном этапе, но в целом, чем больше информации мы можем предоставить компилятору, тем лучше это может сделать с безопасностью и генерированием кода, поэтому вам всегда следует выбирать цикл, когда вы планируйте бесконечно петлю.

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

Итак, как компилятор относится к ним по-другому?

4b9b3361

Ответ 1

На это был дан ответ Reddit. Как вы сказали, компилятор может иметь специальный случай while true, но это не так. Поскольку это не так, компилятор не семантически делает вывод о том, что необъявленная переменная, установленная внутри цикла while true, всегда должна быть инициализирована, если вы выходите из цикла, а для цикла loop:

Это также помогает причине компилятора о циклах, например

let x;
loop { x = 1; break; }
println!("{}", x)

отлично действует, а

let x;
while true { x = 1; break; }
println!("{}", x);

не скомпилируется с "использованием возможно неинициализированной переменной", указывающей на x в println. Во втором случае компилятор не обнаруживает, что тело цикла будет выполняться хотя бы один раз.

(Конечно, мы могли бы в частном случае построить конструкцию while true, чтобы действовать как loop. Я считаю, что это то, что делает Java.)

Ответ 2

Первое, что нужно сказать, с точки зрения производительности, они, вероятно, будут идентичны. Хотя сам Rust не делает ничего особенного с while true, LLVM, скорее всего, делает эту оптимизацию. Компилятор Rust пытается упростить задачу, делегируя оптимизацию LLVM, где это возможно.

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

Хотя некоторые константные выражения могут быть оптимизированы с помощью LLVM, семантика языка не изменяется в зависимости от того, является ли выражение постоянным или нет. Это хорошо, потому что это помогает людям лучше рассуждать о коде.

Просто потому, что true является простым выражением, мы знаем, что оно постоянно. Так же как и true != false и [0; 1].len() == 1. Но как насчет num_cpus::get() == 1? Я на самом деле не знаю, есть ли какие-то цели компиляции, где это может быть постоянным, и мне не нужно было об этом думать!

Ошибка в примере telotortium будет более существенной, если объединить ее с сгенерированным кодом или макросами. Представьте себе макрос, который иногда приводит к простому статическому выражению, подобному true == true, но иногда ссылается на переменную или вызывает функцию. Иногда компилятор может удостовериться, что цикл выполняется один раз, но в других случаях он просто не может. В Rust сейчас ошибка в этом примере всегда будет ошибкой, независимо от того, какой код был сгенерирован для этого условия. Без сюрпризов.

Ответ 3

Одно существенное отличие состоит в том, что loop может возвращать значение, передавая значение в break. while и for не будут:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    assert_eq!(result, 20);
}

Ответ 4

  В чем разница между циклом и временем?

Вы можете спросить, в чем разница между for и while? Ответ будет близок к: Что такое идиома программирования?

Когда вы пишете while condition {}, вы говорите "пока условие истинно, делайте это", но мы можем видеть, что сказать "пока истина истинна, делайте это", излишне. Вот откуда взялся loop, он может очень хорошо выражать бесконечные циклы, потому что мы говорим "цикл на этом". У нас нет никаких условий, это лучше.

Итак, как компилятор относится к ним по-разному?

Я не могу ответить на вопрос "как", но я полагаю, вы хотите знать "почему". Это позволяет компилятору знать, что этот цикл будет запускаться как минимум один раз, как do {} while (condition); из C. Компилятор может использовать эту информацию для создания лучшего кода или предупреждений. Кроме того, вы будете уверены, что цикл будет выполнен там, где цикл while может отсутствовать, потому что компилятор его оптимизирует. Самое интересное, что внутренне Rust использует LLVM, и похоже, что LLVM не имеет способа выразить бесконечный цикл, поэтому в некоторых случаях он вызывает ошибки.