Pular para o conteúdo

O livro · 03

Tipos compostos

book.md · 101 linhas · 2 min de leitura

Objetivo: declarar seus tipos com decl (uma keyword para struct, enum e interface), casar sum types com pattern matching, e conhecer o variant-set.

decl declara struct, enum e interface; o corpo diz qual:

decl Point { x: int; y: int } // campos 'nome: tipo' → struct (produto)
decl Shape { Circle(int); Square } // variantes 'Nome(...)' → enum (soma)
decl Drawable { fn draw() -> []byte } // assinaturas 'fn ...' → interface

Os três compartilham o ato de declarar um contrato, e o corpo desambigua. Membros separam-se por ; ou Newline, nunca vírgula (vírgula é para grupos em (), como argumentos e tuplas).

Métodos são funções externas com receiver (estilo Go); a struct só guarda dados:

decl Dog { nome: string }
fn (d: *Dog) speak() -> string { return "{{d.nome}}: woof" } // receiver '*Dog'
d := Dog{ nome: "Rex" } // literal: campos por ',' (grupo de valores)
io.println(d.speak()) // UFCS: d.speak() ≡ speak(d)

Construtores são funções associadas (receiver = só o tipo, sem nome):

fn (Dog) named(n: string) -> Dog { return Dog{ nome: n } }
rex := Dog.named("Rex") // chamada por ponto

Enum com payload é um sum type; match o destrincha por variante, ligando os campos por posição:

decl Event { Tick; Click(int, int); Quit }
fn describe(e: Event) -> string {
return match e {
Tick => "tick"
Click(x, y) => "click em ({{x}}, {{y}})"
Quit => "quit"
} // domínio fechado: todas as variantes, '_' seria erro
}

Enum sem payload é uma enumeração simples ou máquina de estados:

decl State { Idle; Running; Done }
fn step(s: State) -> State {
return match s {
Idle => Running
Running => Done
Done => Done
}
}

Reúso é composição, com promoção declarada:

decl Animal {}
fn (a: *Animal) speak() -> string { return "..." }
@embeds(Animal, methods)
decl Cat { animal: Animal; nome: string }
c := Cat{ animal: Animal{}, nome: "Mia" }
c.speak() // promovido: chama Animal.speak direto

Shape{Circle} é “um Shape, garantido Circle”: um conjunto de variantes. Em posição de tipo, Nome{...} é variant-set; em posição de valor, Nome{...} é literal de struct (a posição separa):

fn so_clicks(e: Event{Click}) { ... } // aceita só a variante Click (checado no tipo)

É a mesma mecânica dos error-sets do próximo capítulo: um domínio fechado que se sub-seta, com {...} fechando o subconjunto.

alias dá um segundo nome transparente a um tipo que já existe (diferente de decl, que cria tipo novo):

alias UUID = u128 // UUID É u128, intercambiável

Próximo: 04 · Erros