Pular para o conteúdo

O livro · 05

Coleções e strings

book.md · 92 linhas · 2 min de leitura

Objetivo: usar List/Map/Set e a camada funcional, e entender as regras de string (unidades explícitas, interpolação, comparação por byte).

Não são builtin: você as importa. List[T] é um array contíguo que cresce (não linked list):

use collections
var xs := List[int].new()
xs.push(1); xs.push(2); xs.push(3)
io.println("{{xs.len()}} itens")
primeiro := xs.get(0) // Optional[int] (acesso seguro; none fora dos limites)
@requires(i < xs.len())
fn at_seguro(xs: List[int], i: usize) -> int { return xs.at(i) } // 'at' contratado

Acesso é por método (xs.at(i)/xs.get(i)), não xs[i]: [i] cru é só para []T/[N]T/[*]T builtin. get -> Optional (“talvez”), at -> T (“eu garanto”, sob contrato).

Map[K, V] é uma tabela hash; a chave precisa ser hashável, propriedade derivada por reflexão (structs servem sem declarar nada):

m := Map[string, int].new()
m.put("ana", 90)
score := m.get("ana") // Optional[int]
m.update_or_insert("ana", fn(cur) => cur.or(0) + 1) // entry API anti-duplo-lookup

Set[T] é um conjunto hash (add/contains/union/intersection). Estruturas especializadas (Deque, PriorityQueue, SortedMap, Trie, RingBuffer) ficam na lib oficial containers (tier 1), no capítulo 12.

map/filter/fold/collect via UFCS; collect materializa no container que você escolhe:

pares := xs.filter(fn(x) => x % 2 == 0)
dobr := xs.map(fn(x) => x * 2)
soma := xs.fold(0, fn(acc, x) => acc + x)
como_set: Set[int] = primos.collect() // mesmo iterator, container de saída escolhido pelo tipo

string é sempre UTF-8 válido. Tem três visões (.bytes, .codepoints, .chars, esta última de grapheme), e s[i] é proibido (a unidade é ambígua). Você qualifica:

s := "café"
b := s.bytes.len // nº de bytes (campo .len da view)
n := s.chars.len // nº de graphemes
c0 := s.char_at(0) // um grapheme
view := s.chars[1..3] // '..' = view O(1); ':' = cópia O(n)

A interpolação usa {{ }}, via a interface Display (interpolar tipo sem Display é erro de compilação, sem nada de <Object@0x...>):

io.println("{{nome}} fez {{count}} pedidos, total {{total.fixed(2)}}")

A comparação é byte-a-byte: ==/!= (igualdade de bytes), </> (ordem lexicográfica, que alimenta um sort direto). A semântica Unicode (normalização, collation) é método, não operador, e não há ===:

a == b // bytes (o comum, rápido)
a.equals(b, .semantic) // normalização Unicode (puxa tabelas de 'unicode', opt-in)

Crescer uma string segue a regra de mutabilidade de sempre: var muta, por doubling, sem StringBuilder separado (use string.with_capacity(n) quando souber o tamanho):

var buf := string.with_capacity(256)
buf.append("a"); buf.append("b")

Construir a partir de bytes: string.from[u8](bytes) -> Result[string, error{InvalidUtf8}] (valida na borda).

Próximo: 06 · Processos e channels