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

Почему я должен использовать расходящиеся функции?

Прочитав книгу Руста, я наткнулся на интересную тему - расходящиеся функции:

У Rust есть специальный синтаксис для 'расходящихся функций, которые функции, которые не возвращаются:

fn diverges() -> ! {
    panic!("This function never returns!");
}

Функция расхождения может использоваться как любой тип:

let x: i32 = diverges();
let x: String = diverges();

Какими будут случаи использования расходящейся функции? В книге говорится, что

panic!() приводит к сбою текущего потока выполнения с помощью данное сообщение. Поскольку эта функция приведет к сбою, она никогда не будет return, и поэтому он имеет тип !

Это имеет смысл, но я не могу придумать, где еще может быть расходящаяся функция, и она кажется очень локализованной только panic!. Я знаю, что там должны быть какие-то полезные сценарии, почему они вводили расходящиеся функции. Где я, вероятно, увижу расходящиеся функции в Rust?

4b9b3361

Ответ 1

Он имеет несколько применений. Он может использоваться для функций, предназначенных для паники или выхода из программы. panic!() сама по себе является одной из таких функций, но ее также можно применять к функциям, которые обертывают panic!(), например, распечатывают более подробную информацию об ошибках и затем паникуют.

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

Другим возможным применением будет обертка вокруг семейства функций Unix exec, в котором текущий процесс заменяется на тот, который выполняется.

Полезно иметь такой тип, потому что он совместим со всеми другими типами. Чтобы быть безопасным по типу, Rust должен обеспечить, чтобы все ветки оператора match или if возвращали один и тот же тип. Но если есть какие-то ветки, которые недоступны или указывают на ошибку, вам нужно каким-то образом выбросить ошибку, которая будет унифицирована с типом, возвращаемым другими ветвями. Поскольку ! объединяется со всеми типами, его можно использовать в любом таком случае.

Существует интересный RFCобсуждение) на данный момент, который утверждает (частично) для расширение мест, где ! можно использовать, утверждая, что его следует рассматривать как полноценный тип типа () is; ! является типом без значений, которые объединяются со всеми другими типами, тогда как () является отдельным типом с одним значением. Я не уверен, что согласен с полным RFC, но обсуждение обработки ! как полноценного типа интересно, и я думаю, что это может быть предложено отдельно от остальной части RFC.

Обновление. Поскольку я написал выше, часть RFC о продвижении ! к полноценному типу была split в отдельный RFC и объединяется, и в процессе реализации (в настоящее время доступно в ночных сборках за функциональным затвором). Как полнофункциональный тип, его можно использовать в большем количестве контекстов, например, в Result<T, !>, указывающем результат, который никогда не может потерпеть неудачу, или Result<!, E> как тот, который никогда не сможет преуспеть. Они полезны в общих контекстах; если у вас есть какая-то черта, требующая метода для возврата результата, но для этой конкретной реализации это может быть только возможно, вам не нужно заполнять какой-либо фиктивный тип ошибки.

Ответ 2

Как вы указали из книги, Rust нижний тип используется для указания функций, которые не возвращаются. Это включает в себя:

  • panic!()
  • цикл навсегда
  • выйти из программы (кроме возврата из main()), например exit(), подпись которой pub fn exit(code: i32) -> !