Pular para o conteúdo

Conversão de Tipos

Passar um valor de um tipo para outro cai num destes três grupos, por ordem de risco:

GrupoQuando aconteceComo se escreve
AlargamentoNenhuma informação se perdeAutomático, não escreves nada
CastPode perder informação, mas nunca falha(tipo) valor
Conversão de textoPode falhar, porque o texto pode não ser um númerotipo::konverti(texto)

O Kriol converte automaticamente valores numéricos quando a conversão é um alargamento seguro:

DeParaAutomático
boolinteiro ou ponto flutuante✅ Sim
inteiro menor compatívelinteiro maior compatível✅ Sim
inteiroponto flutuante✅ Sim
f32f64 / num✅ Sim
int / i64num / f64✅ Sim
int x = 5;
num y = x; // ok, alargamento automático int para num
fn aceita_num(num n) {
mostran(n);
}
fn inisiu() {
aceita_num(10); // ok, int 10 é alargado para num
}

O caminho contrário nunca é automático. Estreitar um inteiro, ou passar de num para f32, exige um cast:

int grande = 200;
u8 pequeno = grande; // ERRO: não se pode guardar um valor do tipo 'int'
// na variável 'pequeno', que é do tipo 'u8'
u8 certo = (u8) grande; // ok, pedido explicitamente

Como em C, um valor real também se converte implicitamente num inteiro, truncando em direção a zero. Isto vale em declarações, atribuições, argumentos e retornos:

int a = 3.9; // 3
int b = -3.9; // -3
fn metade(num x) int {
divolvi x / 2; // o resultado real é truncado
}

Truncar não é arredondar: 3.9 dá 3 e -3.9 dá -3. Para arredondar valores positivos, soma meio antes de converter: (int) (x + 0.5).

Ao contrário do C, onde um valor fora do intervalo do tipo é comportamento indefinido, no Kriol fica no limite do tipo, e NaN dá 0.

As outras conversões que podem perder informação, como de um inteiro para um inteiro mais estreito, têm de ser pedidas explicitamente, escrevendo o tipo de destino entre parênteses antes do valor, como em C:

int a = (int) 3.9; // 3
num b = (num) a / 2; // 1.5
u8 c = (u8) 300; // 44
bool d = (bool) 5; // sin

O cast é um operador unário: liga mais forte do que os operadores binários, por isso (int) 3.9 + 1 é ((int) 3.9) + 1. Usa parênteses para converter uma expressão inteira: (int) (x + 1.5).

Um cast nunca falha e nunca para o programa, mas pode dar-te um valor que não querias, como no (u8) 300 acima.

DeParaComportamento
realinteiroTrunca em direção a zero (-3.9 dá -3). Valores fora do intervalo ficam no limite do tipo (por exemplo (u8) 1000.5 dá 255) e NaN dá 0
inteirointeiro mais estreitoMantém os bits menos significativos ((u8) 300 dá 44, (i8) 200 dá -56)
inteirorealO valor mais próximo representável
realoutro realArredonda ao tipo de destino (f64 para f32)
boolnúmerosin dá 1 e nau dá 0
númeroboolnau se for zero, sin caso contrário

Repara na diferença entre as duas primeiras linhas: de real para inteiro o valor fica no limite do tipo, mas de inteiro para inteiro os bits que não caibam são descartados, e é por isso que (u8) 300 dá 44 e não 255.

Só números e bool são alvos válidos, e só números e bool se convertem. Estas conversões são erros de compilação:

int n = (int) "5"; // ERRO: não se converte texto
textu t = (textu) 5; // ERRO: o destino não pode ser textu
int m = (int) lista; // ERRO: não se converte um array ou um molde

Para escrever um número como texto, usa uma f-string: textu t = f"{5}";.

Converter texto em número pode falhar (o texto pode não ser um número), por isso não é um cast. Usa tipo::konverti(texto), que usa o mecanismo de erros: falha com um Erru se o texto não for válido.

fn inisiu() : Erru {
int idadi = tenta int::konverti("42");
num altura = num::konverti("1.75") sinon 0.0;
mostran(f"{idadi}; {altura}"); // 42; 1.75
}

Funciona com todos os tipos numéricos (int, num, i8, u8, f32, …) e com bool:

TipoTexto aceite
inteirosSinal opcional (+ ou -) e dígitos (42, -17). O valor tem de caber no tipo: u8::konverti("256") falha
num, f32, f64Sinal opcional, dígitos, parte decimal opcional e expoente opcional (3.25, -2e3). 1. e nan são inválidos. O valor tem de caber no tipo: f32::konverti("1e300") falha
boolsin ou nau

Os espaços no início e no fim do texto são ignorados. As mensagens de erro dizem o que correu mal, por exemplo 'abc' não é um número inteiro válido, '256' não cabe no tipo 'u8' ou 'x' não é um número válido. Um texto com mais de 40 bytes aparece cortado e termina em ....

Se o erro não for tratado com tenta ou sinon, o programa termina nessa chamada com a mensagem do erro. Ao contrário de uma função tua declarada com : Erru, o konverti não gera aviso de compilação quando o erro fica sem tratamento, nem com --strict.

Para converter um valor lido do utilizador, vê Ler números em Entrada de Dados.