Considere o seguinte código de ferrugem:
fn f() -> i32 {
loop {
println!("Infinite loop!");
}
println!("Unreachable");
}
Isso compila (com um aviso) e executa, apesar do tipo de retorno estar errado. Parece que o compilador está OK com o tipo de retorno da ()
última linha, porque detecta que esse código está inacessível.
No entanto, se removermos o último ponto e vírgula:
fn f() -> i32 {
loop {
println!("Infinite loop!");
}
println!("Unreachable")
}
Em seguida, o código não é mais compilado, fornecendo um erro de tipo:
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)
Por que é isso? O tipo de retorno não é o mesmo ()
em ambos os trechos de código?
Nota: Estou interessado em entender por que o compilador Rust se comporta de maneira diferente nesses dois exemplos, ou seja, como o compilador Rust é implementado. Eu não pretendia fazer uma pergunta filosófica sobre como "deveria" se comportar, da perspectiva do design da linguagem (eu entendo que essa pergunta provavelmente seria fora de tópico).
!
o tipo de retorno por causa do loop infinito, o que faz sentido. No segundo caso, há uma expressão de retorno, então o solucionador de inferência de tipo usa isso para inferir o tipo, o que também faz sentido. Eu não acho que isso esteja especificado na referência de idioma, nem acho que isso importe de alguma forma - apenas omita a declaração inacessível e você ficará bem.Respostas:
O tipo de retorno no primeiro bloco de código é realmente
!
(chamado nunca) porque você tem um loop que nunca sai (portanto, o rust fornece um aviso dizendo que é inacessível). O tipo completo seria:fn f() -> !
Eu suspeito que
!
é mais parecido com o tipo 'inferior' em Rust do que qualquer outra coisa. No segundo caso, sua função provavelmente falha em um estágio anterior durante a verificação de tipo devido à incompatibilidade entre i32 e () antes que o compilador chegue à análise de 'inacessibilidade', como ocorre no primeiro exemplo.edit: como sugerido, aqui está a parte relevante do livro sobre ferrugem https://doc.rust-lang.org/book/ch19-04-advanced-types.html#the-never-type-that-never-returns
fonte
!
podem ser coagidas a qualquer outro tipo. "println!
)(Convertendo o primeiro comentário de Sven em uma resposta)
O compilador Rust precisa inferir um tipo para o corpo da função. No primeiro caso, não há expressão de retorno e, aparentemente, o compilador deduz! como o tipo de retorno por causa do loop infinito, o que faz sentido. No segundo caso, há uma expressão de retorno, então o solucionador de inferência de tipo usa isso para inferir o tipo, o que também faz sentido.
Eu não acho que isso esteja especificado na referência de idioma, nem acho que isso importe de alguma forma - apenas omita a declaração inacessível e você ficará bem.
fonte