Funções Divergentes

As funções divergentes nunca retornam. Elas são marcadas usando !, o qual é um tipo vazio.

#![allow(unused)]
fn main() {
fn foo() -> ! {
    panic!("This call never returns.");
}
}

Em oposição à todos os outros tipos, esta não pode ser instanciada, porque o conjunto de todos os possíveis valores que este tipo pode ter é vazio. Nota que, é diferente do tipo (), que tem exatamente um valor possível.

Por exemplo, esta função retorna de costume, embora não exista informação no valor de retorno:

fn some_fn() {
    ()
}

fn main() {
    let _a: () = some_fn();
    println!("This function returns and you can see this line.");
}

Em posição à esta função, que nunca retornará o controlo de volta ao chamador.

#![feature(never_type)]

fn main() {
    let x: ! = panic!("This call never returns.");
    println!("You will never see this line!");
}

Embora isto possa parecer como um conceito abstrato, é de fato muito útil e muitas vezes prático. A principal vantagem deste tipo é que pode ser fundido à qualquer outro e, portanto usado em lugares onde um tipo exato é obrigatório, por exemplo nos ramos de match. Isto permite-nos escrever código como este:

fn main() {
    fn sum_odd_numbers(up_to: u32) -> u32 {
        let mut acc = 0;
        for i in 0..up_to {
            // Repara que o tipo de retorno desta expressão de correspondência
            // de ser u32 por causa do tipo da variável "addition".
            let addition: u32 = match i%2 == 1 {
                // A variável "i" é do tipo u32, que está perfeitamente correta.
                true => i,
                // Por outro lado, a expressão "continue" não retorna u32,
                // mas ainda está bem, porque nunca retorna e portanto não viola os
                // requisitos da expressão de correspondência.
                false => continue,
            };
            acc += addition;
        }
        acc
    }
    println!("Sum of odd numbers up to 9 (excluding): {}", sum_odd_numbers(9));
}

Ela também é o tipo de retorno das função que percorrem os laços de repetição para sempre (por exemplo, loop {}) tal como servidores de rede ou funções que terminam o processo (por exemplo, exit()).