iniciante30 minutosLição 4 de 10

Tipos de Dados

Domine os tipos escalares, tipos compostos, inferência de tipos e anotações de tipo explícitas em Rust

Tipos de Dados

Rust é uma linguagem estaticamente tipada — toda variável deve ter um tipo conhecido em tempo de compilação. O compilador é inteligente em inferir tipos, mas você pode sempre anotá-los explicitamente.

Duas Categorias de Tipos

CategoriaDescriçãoExemplos
EscalarValor únicointeiros, floats, bool, char
CompostoGrupo de valorestuplas, arrays, structs, enums

Tipos Escalares

Tipos Inteiros

Rust oferece inteiros com sinal (i) e sem sinal (u) em vários tamanhos:

TamanhoCom SinalSem SinalFaixa (com sinal)
8 bitsi8u8-128 a 127
16 bitsi16u16-32.768 a 32.767
32 bitsi32u32-2³¹ a 2³¹ -1
64 bitsi64u64-2⁶³ a 2⁶³ -1
128 bitsi128u128-2¹²⁷ a 2¹²⁷ -1
archisizeusizedepende da plataforma (32/64 bits)
rust
fn main() { let a = 42; // i32 (padrão) let b: u8 = 255; // Byte sem sinal explícito let c = 100_000; // Separadores de sublinhado para legibilidade let d = 0xff; // Hexadecimal let e = 0o77; // Octal let f = 0b1111; // Binário let g = b'A'; // Literal de byte (u8, ASCII) // usize/isize para indexar coleções let arr = [1, 2, 3]; let index: usize = 1; println!("{0}", &arr[index]); // 2 }
ℹ️Note

i32 é o tipo inteiro padrão porque é rápido em CPUs modernas e evita problemas de estouro comuns com tipos menores.

Estouro de Inteiro

rust
fn main() { let mut x: u8 = 255; // x = x + 1; // PANICA em modo debug (verificação de estouro) // Wrapping explícito: let y = x.wrapping_add(1); // 0 (envolve) let z = x.saturating_add(1); // 255 (satura no máximo) println!("wrapping: {y}, saturating: {z}"); }
MétodoComportamento
wrapping_addEnvolve (complemento de dois)
saturating_addPara no valor mínimo/máximo
overflowing_addRetorna (resultado, estourou bool)
checked_addRetorna Option (None no estouro)
⚠️Warning

Em modo debug, estouro de inteiro panica. Em modo release, ele envolve silenciosamente. Nunca confie no comportamento de estouro — use métodos explícitos.

Tipos de Ponto Flutuante

rust
fn main() { let x = 2.0; // f64 (padrão, dupla precisão) let y: f32 = 3.0; // f32 (precisão simples) // Operações f64 let ao_quadrado = x.powi(2); // 4.0 let raiz = x.sqrt(); // 1.414... let resto = 5.0 % 2.0; // 1.0 }
TipoPrecisãoTamanhoCaso de Uso
f32~7 dígitos decimais4 bytesGráficos, GPUs
f64~15 dígitos decimais8 bytesComputação geral
⚠️Warning

Floats não implementam Eq ou Ord — NaN e problemas de precisão tornam a comparação não confiável. Use f64::EPSILON para comparação aproximada:

rust
fn approx_eq(a: f64, b: f64) -> bool { (a - b).abs() < f64::EPSILON }

O Tipo Booleano

rust
fn main() { let rust_e_divertido = true; let e_dificil: bool = false; if rust_e_divertido { println!("Rust é divertido!"); } // Conversão para inteiro println!("{}", true as u8); // 1 println!("{}", false as u8); // 0 }

O Tipo Caractere

char tem 4 bytes e representa um Valor Escalar Unicode:

rust
fn main() { let c = 'z'; let z: char = 'ℤ'; let gato_olhos_coracao = '😻'; println!("{c} {z} {gato_olhos_coracao}"); // char como número println!("{}", 'A' as u8); // 65 println!("{}", '😻' as u32); // 128571 }
ℹ️Note

char tem 4 bytes (não 1 como o char do C). Ele suporta Unicode completo, mas não é ASCII — use u8 ou &[u8] para dados em nível de byte.

Tipos Compostos

Tuplas

Tuplas agrupam valores de tipos diferentes. Tamanho fixo, conhecido em tempo de compilação.

rust
fn main() { let tup: (i32, f64, char) = (500, 6.4, 'x'); // Desestruturação let (x, y, z) = tup; println!("{x}, {y}, {z}"); // Notação de ponto (indexada do 0) println!("{}", tup.0); // 500 println!("{}", tup.1); // 6.4 // Tupla unitária (tupla vazia) let unit: () = (); }
PadrãoExemploQuando Usar
Desestruturarlet (a, b) = tupExtrair todos os valores
Acesso por pontotup.0Extrair um valor
Ignorarlet (a, _, _) = tupExtrair alguns valores

Arrays

Arrays têm tamanho fixo, todos os elementos mesmo tipo, armazenados na stack:

rust
fn main() { let arr = [1, 2, 3, 4, 5]; // Anotação de tipo: [tipo; tamanho] let tipado: [i32; 5] = [1, 2, 3, 4, 5]; // Expressão de repetição: [valor; contagem] let zeros = [0; 10]; // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] // Acesso let primeiro = arr[0]; let segundo = arr[1]; // Verificação de limites em execução // let oops = arr[10]; // Panica: índice fora dos limites }
CaracterísticaArrayTupla
Mesmo tipo?SimNão
Tamanho fixo?SimSim
Tipo padrão[T; N](T1, T2, ...)
Acessoarr[i] (verificado em execução)tup.i (tempo de compilação)

Vectors (Prévia)

Vectors são arrays alocados no heap, redimensionáveis:

rust
fn main() { let mut vec = vec![1, 2, 3]; vec.push(4); // Agora [1, 2, 3, 4] println!("{vec:?}"); }

Inferência de Tipos e Anotações

Rust infere tipos na maioria das situações:

rust
fn main() { // Inferência funciona let x = 42; // i32 let y = 3.14; // f64 let cond = true; // bool // Anotações esclarecem intenção let porta: u16 = 8080; let pi: f32 = 3.14159; // Às vezes obrigatório (ambiguidade de tipo) let ambíguo = "olá".parse(); // ERRO: não pode inferir tipo let analisado: u32 = "42".parse().unwrap(); // OK com anotação // Sintaxe Turbofish let n = "100".parse::<i32>().unwrap(); }
Success
| Situação | Exemplo | |-----------|---------| | `parse()` precisa de anotação | `"42".parse::()` ou `let x: i32 = "42".parse()?` | | Inteiro padrão | `let x = 42` → `i32` | | Float padrão | `let x = 3.14` → `f64` | | Genérico de coleção | `Vec::new()` precisa de contexto de tipo |

Aliases de Tipo

rust
type Quilometros = i32; type Thunk = Box<dyn FnOnce() + Send>; fn main() { let distancia: Quilometros = 100; println!("{distancia} km"); }

Tipos Sized e Unsized

CategoriaExemplosTamanho em Tempo de Compilação?
Sizedi32, f64, [i32; 5], StringSim
Unsizedstr, [i32], dyn TraitNão (atrás de ponteiro)

Tipos unsized devem sempre estar atrás de um ponteiro: &str, Box<dyn Trait>.

Perguntas de Prática

  1. Qual é o tipo inteiro padrão em Rust? E o tipo float?
  2. Quantos bytes tem um char em Rust? Como isso difere do C?
  3. Qual a diferença entre uma tupla e um array?
  4. Por que você não pode comparar dois valores f64 com == diretamente?
  5. O que acontece se você acessar um índice de array fora dos limites?
  6. Quando você deve anotar o tipo de uma variável explicitamente?
  7. Para que serve o tipo unitário ()?
  8. Como analisar uma string em um inteiro?
  9. Qual a diferença entre usize e u64?
  10. Quais métodos você pode usar para lidar com estouro de inteiro com segurança?
Progresso40%