Почему Rust допускает код с неправильным типом возврата, но только с конечной точкой с запятой? - PullRequest
8 голосов
/ 21 февраля 2020

Рассмотрим следующий код Rust:

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable");
}

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

Однако, если мы удалим последнюю точку с запятой:

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable")
}

Тогда код больше не компилируется, выдавая ошибку типа:

error[E0308]: mismatched types
  --> src/main.rs:14:5
   |
14 |     println!("Unreachable")
   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
   |
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

Почему это так? Разве тип возврата не одинаков, (), в обоих этих фрагментах кода?


Примечание: Мне интересно понять, почему компилятор Rust ведет себя по-разному на эти два примера, т.е. как реализован компилятор Rust. Я не хотел задавать философский вопрос о том, как он «должен» себя вести с точки зрения языкового дизайна (я понимаю, что такой вопрос, вероятно, был бы вне темы 1020 *).

Ответы [ 2 ]

6 голосов
/ 21 февраля 2020

Тип возврата в первом блоке кода на самом деле ! (называется никогда), потому что у вас есть al oop, который никогда не выходит (поэтому ржавчина выдает предупреждение о том, что он недоступен). Полный тип будет:

fn f() -> !

Я подозреваю, что ! больше похож на тип 'bottom' в Rust, чем на что-либо еще. Во втором случае ваша функция, вероятно, выдает ошибку на более ранней стадии во время проверки типа из-за несоответствия между i32 и (), прежде чем компилятор перейдет к анализу «недостижимости», как это происходит в первом примере.

edit: как и предлагалось, вот соответствующая часть книги о ржавчине https://doc.rust-lang.org/book/ch19-04-advanced-types.html#the никогда не возвращает, что никогда не вернется

0 голосов
/ 22 февраля 2020

(Преобразование первого комментария Свена в ответ)

Компилятору Rust необходимо определить тип для тела функции. В первом случае обратного выражения нет, и, видимо, компилятор выводит! в качестве возвращаемого типа из-за бесконечного l oop, что имеет смысл. Во втором случае есть возвращаемое выражение, поэтому решатель выведения типов использует его для вывода типа, что также имеет смысл.

Я не думаю, что это указано в справочнике по языку, и я не думаю, что это имеет значение в любом случае - просто опустите недостижимое утверждение, и все будет в порядке.

...