Tipos de Dados em Rust
Quando começamos a escrever código em Rust, uma das primeiras descobertas é que tudo tem um tipo muito bem definido. Não é à toa: o compilador depende dessas informações para garantir que o programa seja seguro e previsível. E Rust leva isso a sério.
Como a linguagem é estaticamente tipada, o tipo de cada variável precisa estar claro já na compilação. Em muitos casos, Rust faz esse trabalho sozinho. Mas, quando existem várias possibilidades, ele pede sua ajuda.
Um exemplo simples mostra isso bem:
let valor: u32 = "42".parse().expect("Não é um número");
Se o tipo não for informado, Rust não consegue adivinhar que você queria um número de 32 bits sem sinal.
A partir desse ponto, os tipos começam a se dividir em dois grandes grupos: os escalares, que representam valores únicos, e os compostos, que agrupam vários valores.
Tipos escalares
Esses são os blocos mais básicos da linguagem. Cada valor isolado que você cria será um inteiro, um número de ponto flutuante, um booleano ou um caractere.
Inteiros
Os inteiros são simples de entender. São números sem parte decimal e podem ser positivos ou negativos. Rust oferece várias opções de tamanho, como i32 e u32, e você escolhe conforme a necessidade.
fn main() {
let idade: i32 = 30;
let ranking: u8 = 7;
println!("Idade: {idade}, Ranking: {ranking}");
}
Rust também aceita formatos diferentes de números:
let hex = 0xff; // hexadecimal
let bin = 0b1010_0011; // binário
let byte = b'A'; // byte (valor ASCII)
Quando não souber qual usar, i32 é uma boa escolha. E quando estiver lidando com índices, prefira usize.
Números de ponto flutuante
Para valores com casas decimais, Rust disponibiliza f32 e f64. O segundo é o padrão, oferecendo mais precisão.
fn main() {
let temperatura = 23.8;
let proporcao: f32 = 0.6;
println!("{temperatura}, {proporcao}");
}
Operações numéricas
As operações funcionam como esperado:
let soma = 10 + 5;
let produto = 4 * 20;
let divisao = 8.0 / 3.0;
let truncado = 7 / 2; // vira 3
Booleanos
Simples e diretos: true ou false.
fn main() {
let aprovado = true;
let admin: bool = false;
println!("Aprovado: {aprovado}, Admin: {admin}");
}
Caracteres
O tipo char guarda um único caractere Unicode. Isso significa que letras acentuadas, símbolos e até emojis são válidos.
fn main() {
let letra = 'a';
let simbolo = 'Ω';
let emoji = '😺';
println!("{letra} {simbolo} {emoji}");
}
Tipos compostos
Agora entramos nos tipos que agrupam valores. Rust oferece dois bem importantes: tuplas e arrays.
Tuplas
Uma tupla permite juntar valores diferentes em um único grupo. Elas são úteis quando você quer carregar informações variadas juntas.
fn main() {
let pessoa = ("Ana", 32, 1.70);
let (nome, idade, altura) = pessoa;
println!("{nome}, {idade}, {altura}");
}
E é possível acessar os elementos por índice:
let altura = pessoa.2;
Há ainda a tupla vazia, chamada unit, representada por (). Ela aparece quando uma função não precisa retornar nada.
Arrays
Arrays armazenam valores do mesmo tipo, com tamanho fixo. São diretos e eficientes, ótimos para situações em que a quantidade de elementos não muda.
fn main() {
let notas = [8, 7, 9, 10];
let primeira = notas[0];
println!("Primeira nota: {primeira}");
}
Quando quiser declarar tamanho e tipo:
let lista: [i32; 4] = [10, 20, 30, 40];
Ou criar vários elementos iguais:
let repetidos = [3; 5]; // cria [3, 3, 3, 3, 3]
Arrays são muito seguros, e Rust reforça isso checando o acesso a índices em tempo de execução. Se o índice for inválido, o programa encerra imediatamente:
let valores = [1, 2, 3];
let item = valores[10]; // isso causa erro
Esse comportamento protege seu código de erros que poderiam passar despercebidos em outras linguagens.