Menu

Shapes em Zero: definindo registros parecidos com struct

Shapes são os tipos produto do Zero, parecidos com struct. Veja como declarar, construir valores, ler campos e passar adiante pelas funções — com exemplos das amostras oficiais.

Esta página tem editores executáveis — edite, execute e veja a saída na hora.

Declarando um shape

Um shape é um tipo registro com campos nomeados e tipados:

shape Point {
    x: i32,
    y: i32,
}

Peças:

  • shape introduz a declaração.
  • Point é o nome do tipo.
  • As chaves contêm uma lista de campos, cada um na forma nome: Tipo.

Essa declaração adiciona um novo tipo chamado Point ao escopo atual. Onde quer que você possa usar um tipo embutido como i32, agora você também pode usar Point.

Construindo um valor de shape

Crie uma instância com uma expressão de struct literal:

let point = Point { x: 40, y: 2 }

O literal nomeia o shape e atribui cada campo. Todo campo precisa estar presente — Zero não usa valores padrão de zero ou null em silêncio. Se você esquecer um, o compilador avisa:

{
    "code": "FLD002",
    "message": "missing field: y",
    "line": 4
}

(O código de erro exato pode variar; o princípio de "sem defaults implícitos" é a constante.)

Você pode ler ou anotar o tipo explicitamente se quiser que ele fique visível:

let point: Point = Point { x: 40, y: 2 }

Lendo campos

Acesso a campo usa sintaxe de ponto:

let point = Point { x: 40, y: 2 }
let xVal  = point.x
let yVal  = point.y

point.x lê o campo x. Não há método get_x() — campos são dado puro.

Um exemplo completo

Esse é o exemplo canônico point.0 do repositório da linguagem — clique em Run para tentar:

Passe por ele de cima para baixo:

  1. Declara um shape Point com dois campos i32.
  2. Define uma função sum que recebe um Point e retorna a soma dos campos.
  3. Em main, constrói um Point, chama sum e compara o resultado.

Três passos, três ideias relacionadas a shapes (declarar, construir, acessar) e um efeito — o check world.out.write(...) no fim. Note que sum não toca em World. É uma função pura sobre dados, e a assinatura deixa isso óbvio.

Shapes com campos aninhados

Um shape pode guardar valores de qualquer tipo, inclusive outros shapes:

shape Range {
    start: i32,
    end: i32,
}

shape Segment {
    label: String,
    range: Range,
}

let seg = Segment {
    label: "warmup",
    range: Range { start: 0, end: 10 },
}

Acesso a campo se encadeia como você esperaria:

let len = seg.range.end - seg.range.start

Shapes genéricos

Quando os campos de um shape precisam ser polimórficos no tipo, declare parâmetros de tipo entre sinais de menor/maior:

shape Pair<T, U> {
    left: T,
    right: U,
}

Instâncias fixam os parâmetros em tipos concretos:

let intBytePair: Pair<i32, u8> = Pair { left: 40, right: 2_u8 }
let words: Pair<String, String> = Pair { left: "hello", right: "world" }

Um type alias pode encurtar uma parametrização comum:

type BytePair = Pair<u8, u8>

let bytes: BytePair = Pair { left: 1_u8, right: 2_u8 }

Generics aprofunda parâmetros de tipo — inclusive em funções, não só em shapes.

O que shapes não são

Algumas coisas que você pode esperar de um "struct" em outra linguagem que shapes deliberadamente não incluem:

  • Sem métodos. Uma declaração de shape é só dado. O comportamento mora em funções livres que recebem o shape como parâmetro. Espelha a mesma separação entre dado e efeitos que você vê em funções.
  • Sem herança. Shapes não estendem outros shapes. Se você quer estrutura compartilhada, coloque em um campo comum ou monte um tipo soma com choice.
  • Sem construtores ou destrutores implícitos. A construção é a expressão de struct literal. A limpeza é explícita — quando a biblioteca padrão expõe recursos que precisam de descarte, é feito por APIs no estilo de capacidade em vez de RAII escondido.
  • Sem campos privados. Os campos de um shape são todos acessíveis ao código que enxerga o tipo. A visibilidade é no nível do tipo, não do campo.

O padrão é: shapes são tipos registro simples e previsíveis, e você constrói todo o resto a partir deles.

Quando usar shape vs. choice

Guia rápido:

  • Use um shape quando um valor tem todos esses campos juntos. Um Point sempre tem tanto x quanto y.
  • Use um choice quando um valor é uma de várias alternativas. Um Result é ou um ok ou um err.
  • Use um enum quando as alternativas não carregam dado extra — são só rótulos. Dias da semana, estados simples.

Esses três blocos — shape (e), choice (ou), enum (ou sem payload) — cobrem quase toda necessidade de modelagem de dados.

A seguir: generics

Você viu Pair<T, U> aparecer de passagem. A próxima documentação, generics, explica como parâmetros de tipo funcionam tanto em shapes quanto em funções, incluindo os padrões que aparecem por toda a biblioteca padrão do Zero.

Perguntas frequentes

O que é um shape em Zero?

Um shape é o tipo produto do Zero, parecido com struct — um registro nomeado com campos tipados. Você declara com shape Nome { campo1: T1, campo2: T2 }, constrói valores com Nome { campo1: v1, campo2: v2 } e lê campos com sintaxe de ponto (valor.campo1). Shapes são o bloco de construção para modelar dados estruturados.

Como você cria um valor de shape?

Use uma expressão de struct literal que nomeia o shape e atribui cada campo: let point = Point { x: 40, y: 2 }. Todo campo precisa ser preenchido — Zero não usa valores padrão silenciosos para campos faltantes. A ordem dos campos no literal não precisa bater com a ordem na declaração.

Como shape é diferente de uma classe?

Um shape é só dado — tem campos, mas sem métodos, sem herança, sem construtores implícitos. Funções que operam num shape recebem ele como parâmetro explicitamente. Essa separação mantém a linguagem pequena e torna o custo de construir ou copiar um shape previsível, sem vtables nem destrutores escondidos.

Shapes podem ser genéricos em Zero?

Podem. Declare parâmetros de tipo entre sinais de menor/maior: shape Pair<T, U> { left: T, right: U }. Instâncias fixam esses parâmetros: Pair<i32, u8>. Shapes genéricos aparecem pela biblioteca padrão — Maybe<T>, Span<T> e por aí vai são todos shapes genéricos ou tipos soma construídos sobre a mesma ideia.

Shapes são copiados ou referenciados quando passados a funções?

Passagem por valor é o modelo mental padrão para shapes — quem recebe vê a própria cópia lógica dos dados, não uma referência à ligação de quem chamou. O modelo de memória exato no Zero pré-1.0 ainda está evoluindo (você vai ver ref e mutref nos exemplos da biblioteca padrão para tipos de referência explícitos). Para a maior parte do código de aplicação, trate parâmetros shape como entradas tipadas por valor.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR