Pular para o conteúdo

Enums

Conjuntos fechados de valores nomeados, com valores associados e integração com match.

Declarar#

dataforge
enum Status:
    Rascunho
    Publicado
    Arquivado

Cada membro carrega três coisas:

dataforge
out Status.Publicado.name     # "Publicado" — o identificador
out Status.Publicado.value    # "Publicado" — o valor (padrão: o nome)
out Status.Publicado.index    # 1           — a posição na declaração

O problema que resolve#

Sem enum, estados viram texto solto:

dataforge
pedido := {"status": "publicado"}
given pedido["status"] is "Publicado":     # nunca entra: caixa diferente

Um erro de digitação vira um no silencioso. Com enum, Status.Publicad é erro na hora — e o `dataforge check` acha antes mesmo de rodar:

text
Enum 'Status' has no member 'Publicad'. Members: Rascunho, Publicado, Arquivado

Valores associados#

dataforge
enum Prioridade:
    Baixa := 1
    Media := 5
    Alta := 10
    Critica := 100

enum Moeda:
    Real := "BRL"
    Dolar := "USD"

Sem :=, o valor é o próprio nome. Com :=, é o que você escrever.

A ponte com o mundo externo#

Dentro do programa você quer Moeda.Real. Mas o banco guarda "BRL", a API devolve "BRL", o CSV tem "BRL". O valor é a ponte:

dataforge
vinda_do_banco := "BRL"
moeda := Moeda.from_value(vinda_do_banco)     # Moeda.Real
moeda := Moeda.from_value(entrada) ?? Moeda.Real   # com padrão

from_value devolve void para um valor desconhecido, em vez de inventar um membro. Combinado com ??, isso vira um padrão limpo.

Valores numéricos como ordem#

dataforge
tarefas := [
    {"titulo": "revisar", "prio": Prioridade.Baixa},
    {"titulo": "deploy", "prio": Prioridade.Critica}
]

out sorted(tarefas >> morph t: t["prio"].value)     # [1, 100]

Isso é mais expressivo que depender de .index: o índice reflete a ordem de declaração, o valor reflete a ordem de negócio. Inserir um membro no meio muda os índices, mas não os pesos.

Os utilitários#

ChamadaDevolve
Status.names()["Rascunho", "Publicado", "Arquivado"]
Status.values()os valores
Status.members()os membros, para percorrer
Status.count()3
Status.has("X")yes / no
Status.from_name("X")o membro, ou void
Status.from_value(v)o membro com aquele valor, ou void
dataforge
cycle s in Status.members():
    out $"  {s.index}: {s.name}"

Com match#

dataforge
action acao(luz):
    match luz:
        point Semaforo.Vermelho:
            yield "frear"
        point Semaforo.Amarelo:
            yield "reduzir"
        point Semaforo.Verde:
            yield "acelerar"
        default:
            yield "estado desconhecido"

Máquina de estados#

O padrão completo tem três partes: o enum enumera os estados, uma tabela declara as transições legítimas, e as ações só consultam a tabela.

dataforge
enum Pedido:
    Novo
    Pago
    Enviado
    Entregue

steady TRANSICOES := {
    "Novo": ["Pago"],
    "Pago": ["Enviado"],
    "Enviado": ["Entregue"],
    "Entregue": []
}

action pode_ir(de, para):
    yield para.name in TRANSICOES[de.name]

out pode_ir(Pedido.Novo, Pedido.Pago)        # yes
out pode_ir(Pedido.Novo, Pedido.Entregue)    # no

Nenhum estado inválido é representável, e nenhuma transição inválida é possível. Entregue com lista vazia é um estado terminal.