Objetivo: Construir a lógica de negócios da nossa API. Antes de nos preocuparmos com um banco de dados real, vamos criar um "banco de dados" que vive apenas na memória.
atoms)Em muitas linguagens de programação, se você tem uma lista (ou array) de "todos", você simplesmente "adiciona" (push/append) um novo item a essa lista. A lista original é modificada.
Em Clojure, as estruturas de dados (como mapas {} e vetores []) são imutáveis.
O que "imutável" significa? Significa que, uma vez criado, um valor nunca pode ser alterado.
Vamos ver um exemplo rápido. conj é a função para "adicionar" a um vetor:
;; 1. Criamos um vetor chamado 'meu-vetor'
user=> (def meu-vetor [1 2])
#'user/meu-vetor
;; 2. "Adicionamos" o número 3 a ele
user=> (conj meu-vetor 3)
[1 2 3]
;; 3. Agora, vamos checar o 'meu-vetor' original
user=> meu-vetor
[1 2]
Veja! O meu-vetor original não mudou. A função (conj meu-vetor 3) não modificou o vetor; ela retornou um novo vetor com o item adicionado.
Isso cria um problema para nós:
Se o nosso banco de dados fosse (def todos-db {}), ele seria um mapa vazio para sempre. Como poderíamos "salvar" um novo "todo"? Não poderíamos.
A Solução: O atom (A "Caixa" Segura)
Se os nossos valores não mudam, como gerenciamos o "estado" (coisas que mudam, como um banco de dados)?
Resposta: Nós colocamos nosso valor imutável (um mapa {}) dentro de uma "caixa" de referência. A "caixa" mais comum e simples para isso é um atom.
Pense no atom da seguinte forma:
{...}) é imutável.atom é a caixa em si.Para trabalhar com atoms, usamos três coisas principais:
(atom {...}): O construtor. Usado para criar a caixa e colocar um valor imutável inicial dentro dela.@ (lê-se "deref"): O leitor. Usado para "olhar dentro" da caixa e ver qual valor imutável está lá agora.(swap! ...): O escritor. Usado para trocar o conteúdo da caixa. Ele é "atômico" (daí o nome), o que significa que é seguro de usar mesmo que 1000 pessoas tentem criar um "todo" ao mesmo tempo. O swap! garante que nenhuma escrita seja perdida.