Clojure - Guia rápido
Clojure é uma linguagem de programação funcional dinâmica de alto nível. Clojure é projetado com base na linguagem de programação LISP e tem compiladores que o tornam rodando em Java e em ambientes de execução .Net.
Antes de falarmos sobre Clojure, vamos apenas ter uma descrição rápida da linguagem de programação LISP. Os LISPs têm um pequeno núcleo de linguagem, quase nenhuma sintaxe e um recurso de macro poderoso. Com esses recursos, você pode dobrar o LISP para atender ao seu projeto, em vez do contrário. O LISP existe há muito tempo, desde 1958.
O LISP comum lê uma expressão, avalia e então imprime o resultado. Por exemplo, se você quiser calcular o valor de uma expressão matemática simples de 4 + 6, digite.
USER(1) (+ 4 6)
Clojure tem os seguintes objetivos principais de alto nível como linguagem de programação.
É baseado na linguagem de programação LISP, o que torna suas declarações de código menores do que as linguagens de programação tradicionais.
É uma linguagem de programação funcional.
Ele se concentra na imutabilidade, que é basicamente o conceito de que você não deve fazer nenhuma alteração nos objetos criados no local.
Ele pode gerenciar o estado de um aplicativo para o programador.
Suporta simultaneidade.
Ele abrange linguagens de programação existentes. Por exemplo, Clojure pode fazer uso de todo o ecossistema Java para gerenciamento da execução do código por meio do JVM.
O site oficial do Clojure é https://clojure.org/
Existem várias maneiras de trabalhar com Clojure como linguagem de programação. Veremos duas maneiras de trabalhar com a programação Clojure.
Leiningen - Leiningen é uma ferramenta essencial para criar, construir e automatizar projetos Clojure.
Eclipse Plugin - Existe um plugin chamado CounterClockwise, que está disponível para Eclipse para realizar o desenvolvimento de Clojure no Eclipse IDE.
Instalação Leiningen
Certifique-se de que os seguintes requisitos do sistema sejam atendidos antes de prosseguir com a instalação.
Requisitos de sistema
JDK | JDK 1.7 ou superior |
---|---|
Memória | 2 GB de RAM (recomendado) |
Step 1- Baixe a instalação binária. Vá para o linkhttp://leiningen-wininstallerpara obter o Windows Installer. Clique na opção para iniciar o download do instalador Groovy.
Step 2 - Inicie o instalador e clique no botão Avançar.
Step 3 - Especifique o local da instalação e clique no botão Avançar.
Step 4- A configuração detectará a localização de uma instalação Java existente. Clique no botão Avançar para prosseguir.
Step 5 - Clique no botão Instalar para iniciar a instalação.
Após a conclusão da instalação, você terá a opção de abrir um Clojure REPL, que é um ambiente que pode ser usado para criar e testar seus programas Clojure.
Instalação Eclipse
Certifique-se de que os seguintes requisitos do sistema sejam atendidos antes de prosseguir com a instalação.
Requisitos de sistema
JDK | JDK 1.7 ou superior |
---|---|
Eclipse | Eclipse 4.5 (Marte) |
Step 1- Abra o Eclipse e clique no item Menu. Clique em Ajuda → Eclipse Marketplace.
Step 2- Digite a palavra-chave Clojure na caixa de diálogo que aparece e clique no botão 'Go'. A opção para sentido anti-horário aparecerá, clique no botão Instalar para iniciar a instalação deste plugin.
Step 3 - Na próxima caixa de diálogo, clique no botão Confirmar para iniciar a instalação.
Step 4- Na próxima caixa de diálogo, você será solicitado a aceitar o contrato de licença. Aceite o contrato de licença e clique no botão Concluir para continuar com a instalação.
A instalação começará e, depois de concluída, solicitará que você reinicie o Eclipse.
Depois que o Eclipse for reiniciado, você verá a opção no Eclipse para criar um novo projeto Clojure.
Para entender a sintaxe básica do Clojure, vamos primeiro examinar um programa simples Hello World.
Hello World como um programa completo
Escreva 'Olá, mundo' em um programa Clojure completo. A seguir está um exemplo.
Exemplo
(ns clojure.examples.hello
(:gen-class))
(defn hello-world []
(println "Hello World"))
(hello-world)
As seguintes coisas precisam ser observadas sobre o programa acima.
O programa será escrito em um arquivo chamado main.clj. A extensão 'clj' é o nome da extensão de um arquivo de código clojure. No exemplo acima, o nome do arquivo é main.clj.
A palavra-chave 'defn' é usada para definir uma função. Veremos as funções em detalhes em outro capítulo. Por enquanto, saiba que estamos criando uma função chamada helloworld, que terá nosso código Clojure principal.
Em nosso código Clojure, estamos usando a instrução 'println' para imprimir “Hello World” na saída do console.
Em seguida, chamamos a função hello-world que, por sua vez, executa a instrução 'println'.
O programa acima produz a seguinte saída.
Resultado
Hello World
Forma Geral de uma Declaração
A forma geral de qualquer instrução deve ser avaliada entre colchetes, conforme mostrado no exemplo a seguir.
(+ 1 2)
No exemplo acima, a expressão inteira está entre colchetes. A saída da instrução acima é 3. O operador + atua como uma função em Clojure, que é usado para a adição de numerais. Os valores de 1 e 2 são conhecidos como parameters to the function.
Vamos considerar outro exemplo. Neste exemplo, 'str' é o operador que é usado para concatenar duas strings. As strings “Hello” e “World” são usadas como parâmetros.
(str "Hello" "World")
Exemplo
Se combinarmos as duas instruções acima e escrevermos um programa, ele se parecerá com o seguinte.
(ns clojure.examples.hello
(:gen-class))
(defn Example []
(println (str "Hello World"))
(println (+ 1 2)))
(Example)
Resultado
O programa acima produz a seguinte saída.
Hello World
3
Namespaces
Um namespace é usado para definir um limite lógico entre os módulos definidos no Clojure.
Namespace atual
Isso define o namespace atual no qual o código Clojure atual reside.
Sintaxe
*ns*
Exemplo
Na janela de comando REPL, execute o seguinte comando.
*ns*
Resultado
Quando executamos o comando acima, a saída será adiada dependendo de qual é o namespace atual. A seguir está um exemplo de uma saída. O namespace do código Clojure é -
clojure.examples.hello
(ns clojure.examples.hello
(:gen-class))
(defn Example []
(println (str "Hello World"))
(println (+ 1 2)))
(Example)
Exigir declaração em Clojure
O código Clojure é empacotado em bibliotecas. Cada biblioteca Clojure pertence a um namespace, que é análogo a um pacote Java. Você pode carregar uma biblioteca Clojure com a instrução 'Require'.
Sintaxe
(require quoted-namespace-symbol)
Exemplo
A seguir está um exemplo do uso desta declaração.
(ns clojure.examples.hello
(:gen-class))
(require ‘clojure.java.io’)
(defn Example []
(.exists (file "Example.txt")))
(Example)
No código acima, estamos usando a palavra-chave 'require' para importar o namespace clojure.java.io que possui todas as funções necessárias para a funcionalidade de entrada / saída. Como não temos a biblioteca necessária, podemos usar a função 'arquivo' no código acima.
Comentários em Clojure
Os comentários são usados para documentar seu código. Os comentários de uma única linha são identificados usando ;; em qualquer posição na linha. A seguir está um exemplo.
Exemplo
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println "Hello World"))
(Example)
Delimitadores
No Clojure, as instruções podem ser divididas ou delimitadas usando colchetes ou colchetes.
Exemplo
A seguir estão dois exemplos.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println (+ 1 2 3)))
(Example)
Resultado
O programa acima produz a seguinte saída.
6
Exemplo
A seguir está outro exemplo.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println [+ 1 2 3]))
(Example)
Resultado
O programa acima produz a seguinte saída.
[#object[clojure.core$_PLUS_ 0x10f163b "clojure.core$_PLUS_@10f163b"] 1 2 3]
Espaços em branco
Os espaços em branco podem ser usados no Clojure para dividir os diferentes componentes de uma instrução para maior clareza. Isso pode ser feito com a ajuda do operador vírgula (,).
Por exemplo, as duas instruções a seguir são equivalentes e a saída de ambas as instruções será 15.
(+ 1 2 3 4 5)
(+ 1, 2, 3, 4, 5)
Embora Clojure ignore vírgulas, às vezes as usa para tornar as coisas mais fáceis para o programador ler.
Por exemplo, se você tiver um mapa hash como o seguinte (def a-map {: a 1: b 2: c 3}) e solicitar seu valor na janela REPL, Clojure imprimirá a saída como {: a 1, : b 2,: c 3}.
Os resultados são mais fáceis de ler, especialmente se você estiver observando uma grande quantidade de dados.
Símbolos
No Clojure, os símbolos são equivalentes aos identificadores em outras linguagens de programação. Mas, ao contrário de outras linguagens de programação, o compilador vê os símbolos como valores de string reais. Como um símbolo é um valor, um símbolo pode ser armazenado em uma coleção, passado como um argumento para uma função, etc., assim como qualquer outro objeto.
Um símbolo pode conter apenas caracteres alfanuméricos e '* +! /. : - _? ' mas não deve começar com um numeral ou dois pontos.
A seguir estão exemplos válidos de símbolos.
tutorial-point!
TUTORIAL
+tutorial+
Estrutura do Projeto Clojure
Finalmente, vamos falar sobre uma estrutura de projeto típica para um projeto Clojure. Como o código do Clojure é executado na máquina virtual Java, a maior parte da estrutura do projeto no Clojure é semelhante ao que você encontraria em um projeto Java. A seguir está o instantâneo de uma estrutura de projeto de amostra no Eclipse para um projeto Clojure.
As seguintes coisas importantes precisam ser observadas sobre a estrutura do programa acima.
demo_1 - Este é o pacote no qual o arquivo de código Clojure é colocado.
core.clj - Este é o arquivo de código principal do Clojure, que conterá o código para o aplicativo Clojure.
A pasta Leiningen contém arquivos como clojure-1.6.0.jar, necessários para executar qualquer aplicativo baseado em Clojure.
O arquivo pom.properties conterá informações como groupId, artifactId e versão do projeto Clojure.
O arquivo project.clj contém informações sobre o próprio aplicativo Clojure. A seguir está um exemplo do conteúdo do arquivo de projeto.
(defproject demo-1 "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {
:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"
}
:dependencies [[org.clojure/clojure "1.6.0"]])
REPL (loop read-eval-print) é uma ferramenta para experimentar o código Clojure. Ele permite que você interaja com um programa em execução e teste rapidamente se as coisas funcionam como deveriam. Ele faz isso apresentando um prompt onde você pode inserir o código. Ele então lê sua entrada, avalia, imprime o resultado e faz um loop, apresentando a você um prompt novamente.
Este processo permite um ciclo de feedback rápido que não é possível na maioria dos outros idiomas.
Iniciando uma Sessão REPL
Uma sessão REPL pode ser iniciada em Leiningen digitando o seguinte comando na linha de comando.
lein repl
Isso iniciará a seguinte janela REPL.
Em seguida, você começa a avaliar os comandos do Clojure na janela REPL conforme necessário.
Para iniciar uma sessão REPL no Eclipse, clique na opção Menu, vá para Executar como → Aplicativo Clojure.
Isso iniciará uma nova sessão REPL em uma janela separada junto com a saída do console.
Conceitualmente, REPL é semelhante ao Secure Shell (SSH). Da mesma forma que você pode usar o SSH para interagir com um servidor remoto, o Clojure REPL permite que você interaja com um processo Clojure em execução. Este recurso pode ser muito poderoso porque você pode até anexar um REPL a um aplicativo de produção ao vivo e modificar seu programa enquanto ele é executado.
Variáveis especiais em REPL
REPL inclui algumas variáveis úteis, a amplamente utilizada é a variável especial * 1, * 2 e * 3. Eles são usados para avaliar os resultados das três expressões mais recentes.
O exemplo a seguir mostra como essas variáveis podem ser usadas.
user => "Hello"
Hello
user => "World"
World
user => (str *2 *1)
HelloWorld
No exemplo acima, as duas primeiras strings estão sendo enviadas para a janela de saída REPL como “Hello” e “World” respectivamente. Em seguida, as variáveis * 2 e * 1 são usadas para recuperar as 2 últimas expressões avaliadas.
Clojure oferece uma grande variedade de built-in data types.
Tipos de dados integrados
A seguir está uma lista de tipos de dados que são definidos no Clojure.
Integers - A seguir estão as representações dos inteiros disponíveis no Clojure.
Decimal Integers (Short, Long and Int)- São usados para representar números inteiros. Por exemplo, 1234.
Octal Numbers- São usados para representar números na representação octal. Por exemplo, 012.
Hexadecimal Numbers- São usados para representar números na representação. Por exemplo, 0xff.
Radix Numbers- São usados para representar números na representação da raiz. Por exemplo, 2r1111 em que a raiz é um número inteiro entre 2 e 36, inclusive.
Floating point
O padrão é usado para representar números de ponto flutuante de 32 bits. Por exemplo, 12,34.
A outra representação é a notação científica. Por exemplo, 1.35e-12.
char- Isso define um único literal de caractere. Os caracteres são definidos com o símbolo de folga. Por exemplo, / e.
Boolean - Isso representa um valor booleano, que pode ser verdadeiro ou falso.
String- Estes são literais de texto que são representados na forma de uma cadeia de caracteres. Por exemplo, “Hello World”.
Nil - Isso é usado para representar um valor NULL em Clojure.
Atom- Os átomos fornecem uma maneira de gerenciar o estado independente, síncrono e compartilhado. Eles são um tipo de referência como refs e vars.
Valores Vinculados
Como todos os tipos de dados em Clojure são herdados de Java, os valores limitados são os mesmos da linguagem de programação Java. A tabela a seguir mostra os valores máximos permitidos para os literais numéricos e decimais.
literais | Gamas |
---|---|
Baixo | -32.768 a 32.767 |
int | -2.147.483.648 a 2.147.483.647 |
grandes | -9.223.372.036.854.775.808 a +9.223.372.036.854.775.807 |
flutuador | 1.40129846432481707e-45 a 3.40282346638528860e + 38 |
em dobro | 4.94065645841246544e-324d a 1.79769313486231570e + 308d |
Tipos numéricos de classe
Além dos tipos primitivos, os seguintes tipos de objeto (às vezes chamados de tipos de invólucro) são permitidos.
Nome |
---|
java.lang.Byte |
java.lang.Short |
java.lang.Integer |
java.lang.Long |
java.lang.Float |
java.lang.Double |
Exemplo
O programa a seguir mostra um código de Clojure consolidado para demonstrar os tipos de dados em Clojure.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
;; The below code declares a integer variable
(def x 1)
;; The below code declares a float variable
(def y 1.25)
;; The below code declares a string variable
(def str1 "Hello")
(println x)
(println y)
(println str1))
(Example)
Resultado
O programa acima produz a seguinte saída.
1
1.25
Hello
Em Clojure, variables são definidos pelo ‘def’palavra-chave. É um pouco diferente em que o conceito de variáveis tem mais a ver com vinculação. Em Clojure, um valor está vinculado a uma variável. Uma coisa importante a se notar no Clojure é que as variáveis são imutáveis, o que significa que, para que o valor da variável mude, ela precisa ser destruída e recriada novamente.
A seguir estão os tipos básicos de variáveis no Clojure.
short- Isso é usado para representar um número curto. Por exemplo, 10.
int- Isso é usado para representar números inteiros. Por exemplo, 1234.
long- Isso é usado para representar um número longo. Por exemplo, 10000090.
float- Isso é usado para representar números de ponto flutuante de 32 bits. Por exemplo, 12,34.
char- Isso define um único literal de caractere. Por exemplo, '/ a'.
Boolean - Isso representa um valor booleano, que pode ser verdadeiro ou falso.
String- Estes são literais de texto que são representados na forma de uma cadeia de caracteres. Por exemplo, “Hello World”.
Declarações de variáveis
A seguir está a sintaxe geral para definir uma variável.
Sintaxe
(def var-name var-value)
Onde 'var-name' é o nome da variável e 'var-value' é o valor associado à variável.
Exemplo
A seguir está um exemplo de declaração de variável.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
;; The below code declares a integer variable
(def x 1)
;; The below code declares a float variable
(def y 1.25)
;; The below code declares a string variable
(def str1 "Hello")
;; The below code declares a boolean variable
(def status true))
(Example)
Nomeando Variáveis
O nome de uma variável pode ser composto de letras, dígitos e o caractere de sublinhado. Deve começar com uma letra ou um sublinhado. Letras maiúsculas e minúsculas são distintas porque Clojure, assim como Java, é uma linguagem de programação que diferencia maiúsculas de minúsculas.
Exemplo
A seguir estão alguns exemplos de nomenclatura de variáveis em Clojure.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
;; The below code declares a Boolean variable with the name of status
(def status true)
;; The below code declares a Boolean variable with the name of STATUS
(def STATUS false)
;; The below code declares a variable with an underscore character.
(def _num1 2))
(Example)
Note - Nas declarações acima, devido à distinção entre maiúsculas e minúsculas, status e STATUS são duas variáveis diferentes definidas em Clojure.
O exemplo acima mostra como definir uma variável com um caractere de sublinhado.
Variáveis de impressão
Visto que Clojure usa o ambiente JVM, você também pode usar a função 'println'. O exemplo a seguir mostra como isso pode ser alcançado.
Exemplo
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
;; The below code declares a integer variable
(def x 1)
;; The below code declares a float variable
(def y 1.25)
;; The below code declares a string variable
(def str1 "Hello")
(println x)
(println y)
(println str1))
(Example)
Resultado
O programa acima produz a seguinte saída.
1
1.25
Hello
A operator é um símbolo que diz ao compilador para realizar manipulações matemáticas ou lógicas específicas.
Clojure tem os seguintes tipos de operadores -
- Operadores aritméticos
- Operadores relacionais
- Operadores lógicos
- Operadores bit a bit
Note - No Clojure, os operadores e operandos funcionam da seguinte maneira de sintaxe.
Sintaxe
(operator operand1 operand2 operandn)
Por exemplo,
Exemplo
(+ 1 2)
O exemplo acima faz uma operação aritmética nos números 1 e 2.
Operadores aritméticos
A linguagem Clojure suporta os operadores aritméticos normais como qualquer linguagem. A seguir estão os operadores aritméticos disponíveis no Clojure.
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
+ | Adição de dois operandos | (+ 1 2) dará 3 |
- | Subtrai o segundo operando do primeiro | (- 2 1) dará 1 |
* | Multiplicação de ambos os operandos | (* 2 2) dará 4 |
/ | Divisão do numerador por denominador | (flutuante (/ 3 2)) dará 1,5 |
inc | Operadores incrementais usados para incrementar o valor de um operando em 1 | inc 5 dará 6 |
dezembro | Operadores incrementais usados para diminuir o valor de um operando em 1 | 5 de dezembro dará 4 |
max | Retorna o maior de seus argumentos | no máximo 1 2 3 retornará 3 |
min | Retorna o menor de seus argumentos | min 1 2 3 retornará 1 |
rem | Restante da divisão do primeiro número pelo segundo | rem 3 2 dará 1 |
Operadores Relacionais
Os operadores relacionais permitem a comparação de objetos. A seguir estão os operadores relacionais disponíveis em Clojure.
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
= | Testa a igualdade entre dois objetos | (= 2 2) dará verdadeiro |
não = | Testa a diferença entre dois objetos | (não = 3 2) dará verdadeiro |
< | Verifica se o objeto esquerdo é menor que o operando direito | (<2 3) dará verdadeiro |
<= | Verifica se o objeto esquerdo é menor ou igual ao operando direito | (<= 2 3) dará verdadeiro |
> | Verifica se o objeto esquerdo é maior que o operando direito | (> 3 2) dará verdadeiro |
> = | Verifica se o objeto esquerdo é maior ou igual ao operando direito | (> = 3 2) dará verdadeiro |
Operadores lógicos
Operadores lógicos são usados para avaliar expressões booleanas. A seguir estão os operadores lógicos disponíveis no Groovy.
Mostrar exemplos
Operador | Descrição | Exemplo |
---|---|---|
and | Este é o operador lógico “e” | (ou verdadeiro verdadeiro) dará verdadeiro |
or | Este é o operador lógico “ou” | (e verdadeiro falso) dará falso |
not | Este é o operador lógico “não” | (não falso) dará verdadeiro |
O fragmento de código a seguir mostra como os vários operadores podem ser usados.
Operadores bit a bit
Clojure fornece quatro operadores bit a bit. A seguir estão os operadores bit a bit disponíveis no Clojure.
Mostrar exemplos
Sr. Não. | Operador e descrição |
---|---|
1 | bit-and Este é o operador bit a bit “e” |
2 | bit-or Este é o operador bit a bit “ou” |
3 | bit-xor Este é o bit a bit “xor” ou operador exclusivo 'ou' |
4 | bit-not Este é o operador de negação bit a bit |
A seguir está a tabela verdade mostrando esses operadores.
p | q | p & q | p | q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
operador precedente
Como é o caso com LISPs em geral, não há necessidade de se preocupar com a precedência do operador. Este é um dos benefícios das expressões S e da notação de prefixo. Todas as funções são avaliadas da esquerda para a direita e de dentro para fora. Os operadores em Clojure são apenas funções e tudo está entre parênteses.
Até agora, vimos instruções que são executadas uma após a outra de maneira sequencial. Além disso, as instruções são fornecidas no Clojure para alterar o fluxo de controle na lógica de um programa. Eles são então classificados em declarações de fluxo de controle que veremos em detalhes.
Sr. Não. | Loops e descrição |
---|---|
1 | Declaração While o 'while' A instrução é executada avaliando primeiro a expressão da condição (um valor booleano) e, se o resultado for verdadeiro, as instruções no loop while são executadas. |
2 | Declaração Doseq o ‘doseq’declaração é semelhante à declaração 'para cada' que é encontrada em muitas outras linguagens de programação. A instrução doseq é basicamente usada para iterar em uma sequência. |
3 | Declaração Dotimes o ‘dotimes’ instrução é usada para executar uma instrução 'x' número de vezes. |
4 | Declaração de Loop A forma especial de loop não é como um ‘for’ciclo. O uso de loop é o mesmo que a ligação let. No entanto, o loop define um ponto de recursão |
Decision-making structures exigem que o programador especifique uma ou mais condições a serem avaliadas ou testadas pelo programa, juntamente com uma instrução ou instruções a serem executadas se a condição for determinada como verdadeira e, opcionalmente, outras instruções a serem executadas se a condição for determinada como seja falso.
Sr. Não. | Métodos e Descrição |
---|---|
1 | Declaração If Em Clojure, a condição é uma expressão que a avalia como verdadeira ou falsa. 'If' a condição for verdadeira, então a instrução nº 1 será executada, caso contrário, a instrução nº 2 será executada. |
2 | Se / faço Expressão o ‘if-do’ expressão em Clojure é usada para permitir que várias expressões sejam executadas para cada ramificação da instrução 'if'. |
3 | Declaração aninhada If Múltiplo 'if' declarações embutidas umas nas outras. |
4 | Declaração do Caso Clojure oferece o ‘case’ declaração que é semelhante ao ‘switch’ declaração disponível na linguagem de programação Java. |
5 | Declaração Cond Clojure oferece outra declaração de avaliação chamada de ‘cond’declaração. Esta instrução leva um conjunto de pares de teste / expressão. |
Clojure é conhecido como uma linguagem de programação funcional, portanto, você esperaria ver muita ênfase em como as funções funcionam no Clojure. Este capítulo cobre o que tudo pode ser feito com funções no Clojure.
Sr. Não. | Funções e descrição |
---|---|
1 | Definindo uma função Uma função é definida usando o ‘defn’ macro. |
2 | Funções anônimas Uma função anônima é uma função que não possui um nome associado a ela. |
3 | Funções com vários argumentos As funções Clojure podem ser definidas com zero ou mais parâmetros. Os valores que você passa para as funções são chamadosarguments, e os argumentos podem ser de qualquer tipo. |
4 | Funções Variadicas Clojure oferece a instrução 'case' que é semelhante à instrução 'switch' disponível na linguagem de programação Java. |
5 | Funções de ordem superior Funções de ordem superior (HOFs) são funções que usam outras funções como argumentos. HOFs são uma técnica de programação funcional importante e são muito comumente usados em Clojure. |
Numbers o tipo de dados em Clojure é derivado de classes Java.
Clojure suporta números inteiros e de ponto flutuante.
Um número inteiro é um valor que não inclui uma fração.
Um número de ponto flutuante é um valor decimal que inclui uma fração decimal.
A seguir está um exemplo de números em Clojure.
(def x 5)
(def y 5.25)
Onde 'x' é do tipo Integer e 'y' é o float.
Em Java, as seguintes classes são anexadas aos números definidos em Clojure.
Para realmente ver que os números em Clojure são derivados de classes Java, use o seguinte programa para ver o tipo de números atribuídos ao usar o comando 'def'.
Exemplo
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(def x 5)
(def y 5.25)
(println (type x))
(println (type y)))
(Example)
o ‘type’ comando é usado para produzir a classe associada ao valor atribuído a uma variável.
Resultado
O código acima produzirá a seguinte saída.
Java.lang.long
Java.lang.double
Testes numéricos
As funções de teste a seguir estão disponíveis para números.
Sr. Não. | Números e descrição |
---|---|
1 | zero? Retorna verdadeiro se o número for zero, senão falso. |
2 | pos? Retorna verdadeiro se o número for maior que zero, senão falso. |
3 | neg? Retorna verdadeiro se o número for menor que zero, senão falso. |
4 | até? Retorna verdadeiro se o número for par e lança uma exceção se o número não for um inteiro. |
5 | ímpar? Retorna verdadeiro se o número for ímpar e lança uma exceção se o número não for um inteiro. |
6 | número? Retorna verdadeiro se o número for realmente um Número. |
7 | inteiro? Retorna verdadeiro se o número for um inteiro. |
8 | flutuador? Retorna verdadeiro se o número for um float. |
Vimos a instrução recorrente em um tópico anterior e, enquanto o loop 'for' é um pouco como um loop, recur é um loop real em Clojure.
Se você tem experiência em programação, talvez já tenha ouvido falar da recursão da cauda, que é um dos principais recursos das linguagens funcionais. Esta forma especial recorrente é aquela que implementa a recursão da cauda. Como a palavra “recursão da cauda” indica, recur deve ser chamado na posição da cauda. Em outras palavras, a recorrência deve ser a última coisa a ser avaliada.
O exemplo mais simples da instrução recorrente é usado dentro do loop 'for'. No exemplo a seguir, a instrução recur é usada para alterar o valor da variável 'i' e alimentar o valor da variável de volta para a expressão de loop.
Exemplo
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(loop [i 0]
(when (< i 5)
(println i)
(recur (inc i)))))
(Example)
Resultado
O programa acima produz a seguinte saída.
0
1
2
3
4
Clojure fornece vários métodos auxiliares ao trabalhar com E / S. Ele oferece classes mais fáceis para fornecer as seguintes funcionalidades para arquivos.
- Lendo arquivos
- Gravando em arquivos
- Ver se um arquivo é um arquivo ou diretório
Vamos explorar algumas das operações de arquivo que Clojure tem a oferecer.
Lendo o conteúdo de um arquivo como uma string inteira
Se você deseja obter todo o conteúdo do arquivo como uma string, você pode usar o clojure.core.slurpmétodo. O comando slurp abre um leitor em um arquivo e lê todo o seu conteúdo, retornando uma string.
A seguir está um exemplo de como isso pode ser feito.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(def string1 (slurp "Example.txt"))
(println string1))
(Example)
Se o arquivo contiver as seguintes linhas, elas serão impressas como -
line : Example1
line : Example2
Ler o conteúdo de um arquivo uma linha de cada vez
Se você deseja obter todo o conteúdo do arquivo como uma string, uma linha de cada vez, você pode usar o clojure.java.io/readermétodo. A classe clojure.java.io/reader cria um buffer de leitura, que é usado para ler cada linha do arquivo.
A seguir está um exemplo que mostra como isso pode ser feito.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(with-open [rdr (clojure.java.io/reader "Example.txt")]
(reduce conj [] (line-seq rdr))))
(Example)
If the file contains the following lines, they will be printed as −
line : Example1
line : Example2
The output will be shown as −
["line : Example1" "line : Example2"]
Writing ‘to’ Files
If you want to write ‘to’ files, you can use the clojure.core.spit command to spew entire strings into files. The spit command is the opposite of the slurp method. This method opens a file as a writer, writes content, then closes file.
Following is an example.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(spit "Example.txt"
"This is a string"))
In the above example, if you see the contents of the Example.txt file , you will see the contents of “This is a string”.
Writing ‘to’ Files One Line at a Time
If you want to write ‘to’ files one line at a time, you can use the clojure.java.io.writer class. The clojure.java.io.writer class is used to create a writer stream wherein bytes of data are fed into the stream and subsequently into the file.
Following is an example that shows how the spit command can be used.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(with-open [w (clojure.java.io/writer "Example.txt" :append true)]
(.write w (str "hello" "world"))))
(Example)
When the above code is executed, the line “hello world” will be present in the Example.txt file. The append:true option is to append data to the file. If this option is not specified, then the file will be overwritten whenever data is written to the file.
Checking to See If a File Exists
To check if a file exists, the clojure.java.io.file class can be used to check for the existence of a file. Following is an example that shows how this can be accomplished.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println (.exists (clojure.java.io/file "Example.txt"))))
(Example)
If the file Example.txt exists, the output will be true.
Reading from the Console
To read data from the console, the read-line statement can be used. Following is an example that shows how this can be used.
If you enter the (read-line) command in the REPL window, you will have the chance to enter some input in the console window.
user->(read-line)
Hello World
The above code will produce the following output.
“Hello World”
A String literal is constructed in Clojure by enclosing the string text in quotations. Strings in Clojure need to be constructed using the double quotation marks such as “Hello World”.
Example
Following is an example of the usage of strings in Clojure.
(ns clojure.examples.hello
(:gen-class))
(defn hello-world []
(println "Hello World")
(println "This is a demo application"))
(hello-world)
Output
The above program produces the following output.
Hello World
This is a demo application
Basic String Operations
Clojure has a number of operations that can be performed on strings. Following are the operations.
Sr.No. | String Operations & Description |
---|---|
1 | str The concatenation of strings can be done by the simple str function. |
2 | format The formatting of strings can be done by the simple format function. The format function formats a string using java.lang.String.format. |
3 | count Returns the number of characters in the string. |
4 | subs Returns the substring of ‘s’ beginning at start inclusive, and ending at end (defaults to length of string), exclusive. |
5 | compare Returns a negative number, zero, or a positive number when ‘x’ is logically 'less than', 'equal to', or 'greater than' ‘y’. |
6 | lower-case Converts string to all lower-case. |
7 | upper-case Converts string to all upper-case. |
8 | join Returns a string of all elements in collection, as returned by (seq collection), separated by an optional separator. |
9 | split Splits string on a regular expression. |
10 | split-lines Split strings is based on the escape characters \n or \r\n. |
11 | reverse Reverses the characters in a string. |
12 | replace Replaces all instance of a match in a string with the replacement string. |
13 | trim Removes whitespace from both ends of the string. |
14 | triml Removes whitespace from the left hand side of the string. |
15 | trimr Removes whitespace from the right hand side of the string. |
List is a structure used to store a collection of data items. In Clojure, the List implements the ISeq interface. Lists are created in Clojure by using the list function.
Example
Following is an example of creating a list of numbers in Clojure.
(ns clojure.examples.example
(:gen-class))
(defn example []
(println (list 1 2 3 4)))
(example)
Output
The above code produces the following output.
(1 2 3 4)
Following is an example of creating a list of characters in Clojure.
(ns clojure.examples.example
(:gen-class))
(defn example []
(println (list 'a 'b 'c 'd)))
(example)
The above code produces the following output.
(a b c d)
Following are the list methods available in Clojure.
Sr.No. | Lists & Description |
---|---|
1 | list* Creates a new list containing the items prepended to the rest, the last of which will be treated as a sequence. |
2 | first This function returns the first item in the list. |
3 | nth This function returns the item in the ‘nth’ position in the list. |
4 | cons Returns a new list wherein an element is added to the beginning of the list. |
5 | conj Returns a new list wherein the list is at the beginning and the elements to be appended are placed at the end. |
6 | rest Returns the remaining items in the list after the first item. |
Sets in Clojure are a set of unique values. Sets are created in Clojure with the help of the set command.
Example
Following is an example of the creation of sets in Clojure.
(ns clojure.examples.example
(:gen-class))
(defn example []
(println (set '(1 1 2 2))))
(example)
Output
The above code produces the following output.
#{1,2}
Following are the methods available in Clojure for sets.
Sr.No. | Sets & Description |
---|---|
1 | sorted-set Returns a sorted set of elements. |
2 | get Returns the element at the index position. |
3 | contains? Finds out whether the set contains a certain element or not. |
4 | conj Appends an element to the set and returns the new set of elements. |
5 | disj Disjoins an element from the set. |
6 | union Return a set that is the union of the input sets |
7 | difference Return a set that is the first set without elements of the remaining sets. |
8 | intersection Return a set that is the intersection of the input sets. |
9 | subset? Is set1 a subset of set2? |
10 | superset? Is set1 a superset of set2? |
A Vector is a collection of values indexed by contiguous integers. A vector is created by using the vector method in Clojure.
Example
Following is an example of creating a vector in Clojure.
(ns clojure.examples.example
(:require [clojure.set :as set])
(:gen-class))
(defn example []
(println (vector 1 2 3)))
(example)
Output
The above code produces the following output.
[1 2 3]
Following are the methods available in Clojure.
Sr.No. | Vectors & Description |
---|---|
1 | vector-of Creates a new vector of a single primitive type ‘t’, where ‘t’ is one of :int :long :float :double :byte :short :char or :boolean. |
2 | nth This function returns the item in the nth position in the vector. |
3 | get Returns the element at the index position in the vector. |
4 | conj Appends an element to the vector and returns the new set of vector elements. |
5 | pop For a list or queue, returns a new list/queue without the first item, for a vector, returns a new vector without the last item. |
6 | subvec Returns a sub vector from a starting and ending index. |
A Map is a collection that maps keys to values. Two different map types are provided - hashed and sorted. HashMaps require keys that correctly support hashCode and equals. SortedMaps require keys that implement Comparable, or an instance of Comparator.
A map can be created in two ways, the first is via the hash-map method.
Creation - HashMaps
HashMaps have a typical key value relationship and is created by using hash-map function.
(ns clojure.examples.example
(:gen-class))
(defn example []
(def demokeys (hash-map "z" "1" "b" "2" "a" "3"))
(println demokeys))
(example)
Output
The above code produces the following output.
{z 1, b 2, a 3}
Creation - SortedMaps
SortedMaps have the unique characteristic of sorting their elements based on the key element. Following is an example that shows how the sorted map can be created using the sorted-map function.
(ns clojure.examples.example
(:gen-class))
(defn example []
(def demokeys (sorted-map "z" "1" "b" "2" "a" "3"))
(println demokeys))
(example)
The above code produces the following output.
{a 3, b 2, z 1}
From the above program you can clearly see that elements in the maps are sorted as per the key value. Following are the methods available for maps.
Sr.No. | Maps & Description |
---|---|
1 | get Returns the value mapped to key, not-found or nil if key is not present. |
2 | contains? See whether the map contains a required key. |
3 | find Returns the map entry for the key. |
4 | keys Returns the list of keys in the map. |
5 | vals Returns the list of values in the map. |
6 | dissoc Dissociates a key value entry from the map. |
7 | merge Merges two maps entries into one single map entry. |
8 | merge-with Returns a map that consists of the rest of the maps conj-ed onto the first. |
9 | select-keys Returns a map containing only those entries in map whose key is in keys. |
10 | rename-keys Renames keys in the current HashMap to the newly defined ones. |
11 | map-invert Inverts the maps so that the values become the keys and vice versa. |
Namespaces in Clojure are used to differentiate classes into separate logical spaces just like in Java. Consider the following statement.
(:require [clojure.set :as set])
In the above statement, ‘clojure.set’ is a namespace which contains various classes and methods to be used in the program. For example, the above namespace contains the function called map-invert, which is used to invert a map of key-values. We cannot use this function unless we explicitly tell our program to include this namespace.
Let’s look at the different methods available for namespaces.
Sr.No. | Methods & Description |
---|---|
1 | *ns* This is used to look at your current namespace. |
2 | ns This is used to create a new namespace and associate it with the running program. |
3 | alias Add an alias in the current namespace to another namespace. Arguments are two symbols: the alias to be used and the symbolic name of the target namespace. |
4 | all-ns Returns a list of all namespaces. |
5 | find-ns Finds and returns a particular namespace. |
6 | ns-name Returns the name of a particular namespace. |
7 | ns-aliases Returns the aliases, which are associated with any namespaces. |
8 | ns-map Returns a map of all the mappings for the namespace. |
9 | un-alias Returns a map containing only those entries in map whose key is in keys. |
Exception handling is required in any programming language to handle the runtime errors so that the normal flow of the application can be maintained. Exception usually disrupts the normal flow of the application, which is the reason why we need to use exception handling in our application.
Exception is broadly classified into the following categories −
Checked Exception − The classes that extend Throwable class except RuntimeException and Error are known as checked exceptions. E.g. IOException, SQLException, etc. Checked exceptions are checked at compile-time.
Let’s consider the following program which does an operation on a file called Example.txt. However, there can be always a case wherein the file Example.txt does not exist.
(ns clojure.examples.example
(:gen-class))
;; This program displays Hello World
(defn Example []
(def string1 (slurp "Example.txt"))
(println string1))
(Example)
If the file Example.txt does not exist, then the following exception will be generated by the program.
Caused by: java.io.FileNotFoundException: Example.txt (No such file or
directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at clojure.java.io$fn__9185.invoke(io.clj:229) at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69) at clojure.java.io$fn__9197.invoke(io.clj:258)
at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69)
A partir da exceção acima, podemos ver claramente que o programa gerou uma FileNotFoundException.
Unchecked Exception- As classes que estendem RuntimeException são conhecidas como exceções não verificadas. Por exemplo, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, etc. As exceções não verificadas não são verificadas em tempo de compilação, em vez disso, são verificadas em tempo de execução.
Um caso clássico é a ArrayIndexOutOfBoundsException que acontece quando você tenta acessar um índice de uma matriz que é maior que o comprimento da matriz. A seguir está um exemplo típico desse tipo de erro.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(try
(aget (int-array [1 2 3]) 5)
(catch Exception e (println (str "caught exception: " (.toString e))))
(finally (println "This is our final block")))
(println "Let's move on"))
(Example)
Quando o código acima é executado, a seguinte exceção será levantada.
caught exception: java.lang.ArrayIndexOutOfBoundsException: 5
This is our final block
Let's move on
Erro
O erro é irrecuperável, por exemplo, OutOfMemoryError, VirtualMachineError, AssertionError, etc. Esses são erros dos quais o programa nunca pode se recuperar e que farão com que o programa trave. Agora precisamos de algum mecanismo para capturar essas exceções para que o programa possa continuar a ser executado se essas exceções existirem.
O diagrama a seguir mostra como a hierarquia de exceções em Clojure é organizada. Tudo é baseado na hierarquia definida em Java.
Captura de exceções
Assim como outras linguagens de programação, Clojure fornece o bloco normal 'try-catch' para capturar exceções como e quando elas ocorrem.
A seguir está a sintaxe geral do bloco try-catch.
(try
(//Protected code)
catch Exception e1)
(//Catch block)
Todo o seu código que poderia gerar uma exceção é colocado no Protected code block.
No catch block, você pode escrever um código personalizado para manipular sua exceção para que o aplicativo possa se recuperar da exceção.
Vejamos nosso exemplo anterior que gerou uma exceção de arquivo não encontrado e ver como podemos usar o bloco try catch para capturar a exceção levantada pelo programa.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(try
(def string1 (slurp "Example.txt"))
(println string1)
(catch Exception e (println (str "caught exception: " (.getMessage e))))))
(Example)
O programa acima produz a seguinte saída.
caught exception: Example.txt (No such file or directory)
A partir do código acima, resolvemos o código defeituoso no try block. No bloco catch, estamos apenas capturando nossa exceção e enviando uma mensagem de que ocorreu uma exceção. Portanto, agora temos uma maneira significativa de capturar a exceção, que é gerada pelo programa.
Vários blocos de captura
Pode-se ter vários blocos catch para lidar com vários tipos de exceções. Para cada bloco catch, dependendo do tipo de exceção levantada, você escreveria o código para tratá-la de acordo.
Vamos modificar nosso código anterior para incluir dois blocos catch, um que é específico para nossa exceção de arquivo não encontrado e o outro é para um bloco de exceção geral.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(try
(def string1 (slurp "Example.txt"))
(println string1)
(catch java.io.FileNotFoundException e (println (str "caught file
exception: " (.getMessage e))))
(catch Exception e (println (str "caught exception: " (.getMessage e)))))
(println "Let's move on"))
(Example)
O programa acima produz a seguinte saída.
caught file exception: Example.txt (No such file or directory)
Let's move on
A partir da saída acima, podemos ver claramente que nossa exceção foi capturada pelo bloco de captura 'FileNotFoundException' e não pelo geral.
Finalmente Bloco
O bloco finalmente segue um bloco try ou um bloco catch. Um bloco final de código sempre é executado, independentemente da ocorrência de uma Exceção.
Usar um bloco finally permite que você execute quaisquer instruções do tipo de limpeza que deseja executar, não importa o que aconteça no código protegido. A seguir está a sintaxe para este bloco.
(try
(//Protected code)
catch Exception e1)
(//Catch block)
(finally
//Cleanup code)
Vamos modificar o código acima e adicionar o bloco finally de código. A seguir está o trecho de código.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(try
(def string1 (slurp "Example.txt"))
(println string1)
(catch java.io.FileNotFoundException e (println (str "caught file
exception: " (.getMessage e))))
(catch Exception e (println (str "caught exception: " (.getMessage e))))
(finally (println "This is our final block")))
(println "Let's move on"))
(Example)
O programa acima produz a seguinte saída.
caught file exception: Example.txt (No such file or directory)
This is our final block
Let's move on
No programa acima, você pode ver que o bloco final também é implementado depois que o bloco catch captura a exceção necessária.
Como Clojure deriva seu tratamento de exceções de Java, semelhante a Java, os seguintes métodos estão disponíveis em Clojure para gerenciar as exceções.
public String getMessage()- Retorna uma mensagem detalhada sobre a exceção que ocorreu. Esta mensagem é inicializada no construtor Throwable.
public Throwable getCause() - Retorna a causa da exceção conforme representado por um objeto Throwable.
public String toString() - Retorna o nome da classe concatenada com o resultado de getMessage ().
public void printStackTrace() - Imprime o resultado de toString () junto com o rastreamento de pilha em System.err, o fluxo de saída de erro.
public StackTraceElement [] getStackTrace()- Retorna uma matriz contendo cada elemento no rastreamento de pilha. O elemento no índice 0 representa o topo da pilha de chamadas e o último elemento na matriz representa o método na parte inferior da pilha.
public Throwable fillInStackTrace() - Preenche o rastreamento da pilha deste objeto Throwable com o rastreamento da pilha atual, adicionando a qualquer informação anterior no rastreamento da pilha.
A seguir está o código de exemplo que usa alguns dos métodos listados acima.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(try
(def string1 (slurp "Example.txt"))
(println string1)
(catch java.io.FileNotFoundException e (println (str "caught file
exception: " (.toString e))))
(catch Exception e (println (str "caught exception: " (.toString e))))
(finally (println "This is our final block")))
(println "Let's move on"))
(Example)
O programa acima produz a seguinte saída.
caught file exception: java.io.FileNotFoundException: Example.txt (No such file
or directory)
This is our final block
Let's move on
Sequences são criados com a ajuda do ‘seq’comando. A seguir está um exemplo simples de uma criação de sequência.
(ns clojure.examples.example
(:gen-class))
;; This program displays Hello World
(defn Example []
(println (seq [1 2 3])))
(Example)
O programa acima produz a seguinte saída.
(1 2 3)
A seguir estão os vários métodos disponíveis para sequências.
Sr. Não. | Métodos e Descrição |
---|---|
1 | contras Retorna uma nova sequência onde 'x' é o primeiro elemento e 'seq' é o resto. |
2 | conj Retorna uma nova sequência em que 'x' é o elemento adicionado ao final da sequência. |
3 | concat Isso é usado para concatear duas sequências. |
4 | distinto Usado apenas para garantir que elementos distintos sejam adicionados à sequência. |
5 | reverter Inverte os elementos na sequência. |
6 | primeiro Retorna o primeiro elemento da sequência. |
7 | último Retorna o último elemento da sequência. |
8 | descansar Retorna toda a sequência, exceto o primeiro elemento. |
9 | ordenar Retorna uma sequência classificada de elementos. |
10 | solta Descarta elementos de uma sequência com base no número de elementos que precisam ser removidos. |
11 | levar por último Obtém a última lista de elementos da sequência. |
12 | levar Obtém a primeira lista de elementos da sequência. |
13 | dividir em Divide a sequência de itens em duas partes. Um local é especificado no qual a divisão deve acontecer. |
UMA regular expressioné um padrão usado para localizar substrings no texto. Expressões regulares são usadas em uma variedade de linguagens de programação e muito usadas em linguagens de programação do tipo LISP.
A seguir está um exemplo de uma expressão regular.
//d+
A expressão regular acima é usada para encontrar mais uma ocorrência de um dígito em uma string. Os caracteres // são usados para garantir que os caracteres 'd' e '+' sejam usados para representar uma expressão regular.
Em geral, as expressões regulares funcionam com o seguinte conjunto de regras.
Existem dois caracteres posicionais especiais usados para denotar o início e o fim de uma linha: circunflexo (∧) e cifrão ($):
As expressões regulares também podem incluir quantificadores. O sinal de mais (+) representa uma ou mais vezes, aplicado ao elemento anterior da expressão. O asterisco (*) é usado para representar zero ou mais ocorrências. O ponto de interrogação (?) Denota zero ou uma vez.
O metacaractere {e} é usado para corresponder a um número específico de instâncias do caractere anterior.
Em uma expressão regular, o símbolo de ponto (.) Pode representar qualquer caractere. Isso é descrito como o caractere curinga.
Uma expressão regular pode incluir classes de caracteres. Um conjunto de caracteres pode ser dado como uma sequência simples de caracteres entre os metacaracteres [e] como em [aeiou]. Para intervalos de letras ou números, você pode usar um separador de traço como em [a – z] ou [a – mA – M]. O complemento de uma classe de caracteres é denotado por um acento circunflexo à esquerda entre colchetes como em [∧a – z] e representa todos os caracteres além dos especificados.
Os métodos a seguir estão disponíveis para expressões regulares.
Sr. Não. | Métodos e Descrição |
---|---|
1 | re-padrão Retorna uma instância de java.util.regex.Pattern. Isso é então usado em outros métodos para correspondência de padrões. |
2 | reencontrar Retorna a próxima correspondência de regex, se houver, da string para o padrão, usando java.util.regex.Matcher.find () |
3 | substituir A função de substituição é usada para substituir uma substring em uma string por um novo valor de string. A busca pela substring é feita com o uso de um pattern. |
4 | substitua primeiro A função de substituição é usada para substituir uma substring em uma string por um novo valor de string, mas apenas para a primeira ocorrência da substring. A busca pela substring é feita com o uso de um pattern. |
Predicatessão funções que avaliam uma condição e fornecem um valor verdadeiro ou falso. Vimos funções de predicado nos exemplos do capítulo sobre números. Vimos funções como 'mesmo?' que é usado para testar se um número é par ou não, ou 'neg?' que é usado para testar se um número é maior que zero ou não. Todas essas funções retornam um valor verdadeiro ou falso.
A seguir está um exemplo de predicados em Clojure.
(ns clojure.examples.example
(:gen-class))
;; This program displays Hello World
(defn Example []
(def x (even? 0))
(println x)
(def x (neg? 2))
(println x)
(def x (odd? 3))
(println x)
(def x (pos? 3))
(println x))
(Example)
O programa acima produz a seguinte saída.
true
false
true
true
Além das funções de predicado normais, Clojure fornece mais funções para predicados. Os métodos a seguir estão disponíveis para predicados.
Sr. Não. | Métodos e Descrição |
---|---|
1 | todo predador Pega um conjunto de predicados e retorna uma função 'f' que retorna verdadeiro se todos os seus predicados de composição retornam um valor lógico verdadeiro contra todos os seus argumentos, caso contrário, retorna falso. |
2 | cada? Retorna verdadeiro se o predicado for verdadeiro para todos os valores, senão falso. |
3 | alguns Retorna o primeiro valor verdadeiro lógico para qualquer valor de predicado de x na coleção de valores. |
4 | nenhum? Retorna falso se qualquer um dos predicados dos valores em uma coleção for logicamente verdadeiro, caso contrário, verdadeiro. |
Destructuring é uma funcionalidade do Clojure, que permite extrair valores de uma estrutura de dados, como um vetor, e vinculá-los a símbolos sem ter que atravessar explicitamente a estrutura de dados.
Vejamos um exemplo do que exatamente significa desestruturação e como isso acontece.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def my-vector [1 2 3 4])
(let [[a b c d] my-vector]
(println a b c d)))
(Example)
O programa acima produz a seguinte saída.
Resultado
1 2 3 4
No exemplo acima, as seguintes coisas devem ser observadas -
Estamos definindo um vetor de inteiros como 1, 2, 3 e 4.
Estamos então usando o ‘let’ para atribuir 4 variáveis (a, b, c e d) à variável my-vetor diretamente.
Se executarmos o ‘println’ declaração sobre as quatro variáveis, podemos ver que eles já foram atribuídos aos valores no vetor, respectivamente.
Portanto, o clojure desestruturou a variável my-vector, que tinha quatro valores quando foi atribuída usando a instrução 'let'. Os quatro valores desconstruídos foram então atribuídos aos quatro parâmetros em conformidade.
Se houver variáveis em excesso que não tenham um valor correspondente ao qual possam ser atribuídas, elas receberão o valor nulo. O exemplo a seguir esclarece esse ponto.
Exemplo
(ns clojure.examples.hello
(:gen-class))
(defn Example []
(def my-vector [1 2 3 4])
(let [[a b c d e] my-vector]
(println a b c d e)))
(Example)
O programa acima produz a seguinte saída. Você pode ver na saída que, como a última variável 'e' não tem um valor correspondente no vetor, ela é nula.
Resultado
1 2 3 4 nil
o resto
A variável 'the-rest' é usada para armazenar os valores restantes, que não podem ser atribuídos a nenhuma variável.
Um exemplo de como isso é usado é mostrado no programa a seguir.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def my-vector [1 2 3 4])
(let [[a b & the-rest] my-vector]
(println a b the-rest)))
(Example)
O programa acima produz a seguinte saída. Na saída, você pode ver claramente que os valores de 3 e 4 não podem ser atribuídos a nenhuma variável, portanto, eles são atribuídos à variável 'o resto'.
Resultado
1 2 (3 4)
Mapas de Destruição
Assim como os vetores, os mapas também podem ser desestruturados. A seguir está um exemplo de como isso pode ser feito.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def my-map {"a" 1 "b" 2})
(let [{a "a" b "b"} my-map]
(println a b)))
(Example)
O programa acima produz a seguinte saída. No programa, você pode ver claramente que os valores do mapa de “a” e “b” são atribuídos às variáveis de a e b.
Resultado
1 2
Da mesma forma, no caso de vetores, se não houver um valor correspondente no mapa quando a desestruturação ocorrer, então a variável receberá um valor nulo.
A seguir está um exemplo.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def my-map {"a" 1 "b" 2})
(let [{a "a" b "b" c "c"} my-map]
(println a b c)))
(Example)
O programa acima produz a seguinte saída.
Resultado
1 2 nil
Como a estrutura Clojure é derivada de classes Java, pode-se usar as classes de data e hora disponíveis em Java no Clojure. oclass date representa um instante específico no tempo, com precisão de milissegundos.
A seguir estão os métodos disponíveis para a classe de data e hora.
java.util.Date
Isso é usado para criar o objeto de data em Clojure.
Sintaxe
A seguir está a sintaxe.
java.util.Date.
Parameters - Nenhum.
Return Value - Aloca um objeto Date e o inicializa de forma que represente a hora em que foi alocado, medido no milissegundo mais próximo.
Exemplo
Um exemplo de como isso é usado é mostrado no programa a seguir.
(ns example)
(defn Example []
(def date (.toString (java.util.Date.)))
(println date))
(Example)
Resultado
O programa acima produz a seguinte saída. Isso dependerá da data e hora atuais no sistema, no qual o programa está sendo executado.
Tue Mar 01 06:11:17 UTC 2016
java.text.SimpleDateFormat
Isso é usado para formatar a saída de data.
Sintaxe
A seguir está a sintaxe.
(java.text.SimpleDateFormat. format dt)
Parameters- 'formato' é o formato a ser usado ao formatar a data. 'dt' é a data que deve ser formatada.
Return Value - Uma saída de data formatada.
Exemplo
Um exemplo de como isso é usado é mostrado no programa a seguir.
(ns example)
(defn Example []
(def date (.format (java.text.SimpleDateFormat. "MM/dd/yyyy") (new java.util.Date)))
(println date))
(Example)
Resultado
O programa acima produz a seguinte saída. Isso dependerá da data e hora atuais no sistema, no qual o programa está sendo executado.
03/01/2016
consiga tempo
Retorna o número de milissegundos desde 1º de janeiro de 1970, 00:00:00 GMT representado por este objeto Date.
Sintaxe
A seguir está a sintaxe.
(.getTime)
Parameters - Nenhum.
Return Value - O número de milissegundos desde 1º de janeiro de 1970, 00:00:00 GMT representado por esta data.
Exemplo
Um exemplo de como isso é usado é mostrado no programa a seguir.
(ns example)
(import java.util.Date)
(defn Example []
(def date (.getTime (java.util.Date.)))
(println date))
(Example)
Resultado
O programa acima produz a seguinte saída. Isso dependerá da data e hora atuais no sistema, no qual o programa está sendo executado.
1456812778160
Atomssão um tipo de dados no Clojure que fornecem uma maneira de gerenciar o estado independente, síncrono e compartilhado. Um átomo é como qualquer tipo de referência em qualquer outra linguagem de programação. O principal uso de um átomo é manter as estruturas de dados imutáveis de Clojure. O valor mantido por um átomo é alterado com oswap! method.
Internamente, troque! lê o valor atual, aplica a função a ele e tenta compará-lo e configurá-lo. Como outro thread pode ter alterado o valor no intervalo de tempo, pode ser necessário tentar novamente e o faz em um loop de rotação. O efeito líquido é que o valor sempre será o resultado da aplicação da função fornecida a um valor atual, atomicamente.
Exemplo
Os átomos são criados com a ajuda do método do átomo. Um exemplo do mesmo é mostrado no programa a seguir.
(ns clojure.examples.example
(:gen-class))
(defn example []
(def myatom (atom 1))
(println @myatom))
(example)
Resultado
O programa acima produz o seguinte resultado.
1
O valor de átomo é acessado usando o símbolo @. Clojure possui algumas operações que podem ser realizadas em átomos. A seguir estão as operações.
Sr. Não. | Operações e descrição |
---|---|
1 | Redefinir! Define o valor do átomo para um novo valor sem levar em consideração o valor atual. |
2 | comparar e definir! Atomicamente define o valor do átomo para o novo valor se e somente se o valor atual do átomo for idêntico ao valor antigo mantido pelo átomo. Retorna verdadeiro se set acontecer, senão retorna falso. |
3 | troca! Atomicamente troca o valor do átomo por um novo com base em uma função específica. |
Em Clojure, metadataé usado para anotar os dados em uma coleção ou para os dados armazenados em um símbolo. Isso normalmente é usado para anotar dados sobre tipos para o compilador subjacente, mas também pode ser usado para desenvolvedores. Metadados não são considerados parte do valor do objeto. Ao mesmo tempo, os metadados são imutáveis.
As seguintes operações são possíveis em Clojure com relação aos metadados.
Sr. Não. | Operações e descrição |
---|---|
1 | meta-com Esta função é usada para definir um mapa de metadados para qualquer objeto. |
2 | meta Esta função é usada para ver se algum metadado está associado a um objeto. |
3 | variar-meta Retorna um objeto do mesmo tipo e valor do objeto original, mas com metadados combinados. |
StructMapssão usados para criar estruturas em Clojure. Por exemplo, se você deseja criar uma estrutura composta por um nome de funcionário e um ID de funcionário, pode fazer isso com StructMaps.
As seguintes operações são possíveis em Clojure com relação a StructMaps.
Sr. Não. | Operações e descrição |
---|---|
1 | defstruir Esta função é usada para definir a estrutura necessária. |
2 | estrutura Esta função é usada para definir um objeto de estrutura do tipo, que é criado pela operação defstruct. |
3 | struct-map Esta função é usada para atribuir valores especificamente a valores de chave, definindo explicitamente quais valores são atribuídos a quais chaves na estrutura. |
4 | Acessando Campos Individuais Campos individuais da estrutura podem ser acessados acessando as chaves junto com o objeto de estrutura. |
5 | Natureza Imutável Por padrão, as estruturas também são imutáveis, portanto, se tentarmos alterar o valor de uma chave específica, ele não mudará. |
6 | Adicionando uma Nova Chave à Estrutura Como as estruturas são imutáveis, a única maneira de adicionar outra chave à estrutura é por meio da criação de uma nova estrutura. Um exemplo de como isso pode ser alcançado é mostrado no programa a seguir. |
Como apontado muitas vezes, Clojure é uma linguagem de programação em que muitos dos tipos de dados são imutáveis, o que significa que a única maneira de alterar o valor de uma variável é criar uma nova variável e atribuir o novo valor a ela. No entanto, Clojure fornece alguns elementos, que podem criar um estado mutável. Vimos que isso pode ser alcançado com o tipo de dados atom. A outra maneira de fazer isso é por meio de agentes.
Agentsfornecer mudança independente e assíncrona de locais individuais. Os agentes são vinculados a um único local de armazenamento por toda a vida e permitem que a mutação desse local (para um novo estado) ocorra apenas como resultado de uma ação. Ações são funções (com, opcionalmente, argumentos adicionais) que são aplicadas de forma assíncrona ao estado de um Agente e cujo valor de retorno se torna o novo estado do Agente.
As seguintes operações são possíveis em Clojure com relação a Agentes.
Sr. Não. | Operações e descrição |
---|---|
1 | agente Um agente é criado usando o comando do agente. |
2 | enviar Esta função é usada para enviar um valor ao agente. |
3 | agentes de desligamento Esta função é usada para encerrar qualquer agente em execução. |
4 | despedida Existem casos em que um agente é atribuído a uma função que é de natureza de bloqueio. |
5 | aguardar Como há um atraso quando um valor de um agente é atualizado, Clojure forneceu uma função 'esperar por' que é usada para especificar o tempo em milissegundos para esperar pela atualização do agente. |
6 | aguardam Bloqueia o encadeamento atual (indefinidamente!) Até que todas as ações despachadas até agora, deste encadeamento ou agente, para o (s) agente (s) tenham ocorrido. Bloqueará em agentes com falha. |
7 | erro de agente Retorna a exceção lançada durante uma ação assíncrona do agente, se o agente falhar. Retorna nulo se o agente não falhar. |
Watcherssão funções adicionadas a tipos de variáveis, como átomos e variáveis de referência, que são chamadas quando um valor do tipo de variável muda. Por exemplo, se o programa de chamada alterar o valor de uma variável atom e se uma função de observador for anexada à variável atom, a função será chamada assim que o valor do átomo for alterado.
As funções a seguir estão disponíveis no Clojure for Watchers.
adicionar relógio
Adiciona uma função de observação a uma referência de agente / átomo / var / ref. O relógio‘fn’deve ser um 'fn' de 4 args: uma chave, a referência, seu estado antigo, seu estado novo. Sempre que o estado da referência pode ter sido alterado, quaisquer relógios registrados terão suas funções chamadas.
Sintaxe
A seguir está a sintaxe.
(add-watch variable :watcher
(fn [key variable-type old-state new-state]))
Parameters- 'variável' é o nome do átomo ou variável de referência. 'tipo de variável' é o tipo de variável, seja átomo ou variável de referência. 'old-state & new-state' são parâmetros que manterão automaticamente o valor antigo e o novo da variável. 'key' deve ser única por referência e pode ser usada para remover o relógio com remove-watch.
Return Value - Nenhum.
Exemplo
Um exemplo de como isso é usado é mostrado no programa a seguir.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def x (atom 0))
(add-watch x :watcher
(fn [key atom old-state new-state]
(println "The value of the atom has been changed")
(println "old-state" old-state)
(println "new-state" new-state)))
(reset! x 2))
(Example)
Resultado
O programa acima produz a seguinte saída.
The value of the atom has been changed
old-state 0
new-state 2
remover-assistir
Remove um relógio que foi anexado a uma variável de referência.
Sintaxe
A seguir está a sintaxe.
(remove-watch variable watchname)
Parameters- 'variável' é o nome do átomo ou variável de referência. 'watchname' é o nome dado ao relógio quando a função de relógio é definida.
Return Value - Nenhum.
Exemplo
Um exemplo de como isso é usado é mostrado no programa a seguir.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def x (atom 0))
(add-watch x :watcher
(fn [key atom old-state new-state]
(println "The value of the atom has been changed")
(println "old-state" old-state)
(println "new-state" new-state)))
(reset! x 2)
(remove-watch x :watcher)
(reset! x 4))
(Example)
Resultado
O programa acima produz a seguinte saída.
The value of the atom has been changed
old-state 0
new-state 2
Você pode ver claramente no programa acima que o segundo comando de reinicialização não aciona o observador, pois foi removido da lista do observador.
Em qualquer idioma, Macrossão usados para gerar código embutido. Clojure não é exceção e fornece recursos de macro simples para desenvolvedores. As macros são usadas para escrever rotinas de geração de código, que fornecem ao desenvolvedor uma maneira poderosa de adaptar a linguagem às necessidades do desenvolvedor.
A seguir estão os métodos disponíveis para macros.
defmacro
Esta função é usada para definir sua macro. A macro terá um nome de macro, uma lista de parâmetros e o corpo da macro.
Sintaxe
A seguir está a sintaxe.
(defmacro name [params*] body)
Parameters- 'nome' é o nome da macro. 'params' são os parâmetros atribuídos à macro. 'corpo' é o corpo da macro.
Return Value - Nenhum.
Exemplo
Um exemplo de como isso é usado é mostrado no programa a seguir.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(defmacro Simple []
(println "Hello"))
(macroexpand '(Simple)))
(Example)
Resultado
O programa acima produz a seguinte saída.
Hello
No programa acima, você pode ver que a macro 'Simples' é expandida em linha para 'println' “Olá”. Macros são semelhantes a funções, com a única diferença de que os argumentos para um formulário são avaliados no caso de macros.
macro-expansão
Isso é usado para expandir uma macro e colocar o código embutido no programa.
Sintaxe
A seguir está a sintaxe.
(macroexpand macroname)
Parameters - 'macroname' é o nome da macro que precisa ser expandida.
Return Value - A macro expandida.
Exemplo
Um exemplo de como isso é usado é mostrado no programa a seguir.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(defmacro Simple []
(println "Hello"))
(macroexpand '(Simple)))
(Example)
Resultado
O programa acima produz a seguinte saída.
Hello
Macro com Argumentos
As macros também podem ser usadas para aceitar argumentos. A macro pode receber qualquer número de argumentos. O exemplo a seguir mostra como os argumentos podem ser usados.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(defmacro Simple [arg]
(list 2 arg))
(println (macroexpand '(Simple 2))))
(Example)
O exemplo acima coloca um argumento na macro Simples e então usa o argumento para adicionar o valor do argumento a uma lista.
Resultado
O programa acima produz a seguinte saída.
(2 2)
Reference valuessão outra maneira de o Clojure trabalhar com a demanda de variáveis mutáveis. Clojure fornece tipos de dados mutáveis, como átomos, agentes e tipos de referência.
A seguir estão as operações disponíveis para valores de referência.
Sr. Não. | Operações e descrição |
---|---|
1 | ref Isso é usado para criar um valor de referência. Ao criar um valor de referência, existe a opção de fornecer uma função de validador, que irá validar o valor criado. |
2 | ref-set Esta função é usada para definir o valor de uma referência para um novo valor, independentemente de qualquer que seja o valor mais antigo. |
3 | alterar Esta função é usada para alterar o valor de um tipo de referência, mas de maneira segura. Isso é executado em um thread, que não pode ser acessado por outro processo. |
4 | dosync Executa a expressão (em um do implícito) em uma transação que abrange a expressão e todas as chamadas aninhadas. |
5 | comutar Commute também é usado para alterar o valor de um tipo de referência, assim como alter e ref-set. |
Para usar a funcionalidade de banco de dados, certifique-se de primeiro fazer o download do jdbc files do seguinte url - https://codeload.github.com/clojure/java.jdbc/zip/master
Você encontrará um arquivo zip que contém os drivers necessários para que o Clojure possa se conectar a bancos de dados. Depois que o arquivo zip for extraído, certifique-se de adicionar o local descompactado ao seu classpath.
O arquivo principal para conectividade de banco de dados é um arquivo chamado jdbc.clj no local clojure / java.
O conector clojure jdbc oferece suporte a uma ampla variedade de bancos de dados, alguns dos quais são os seguintes.
- H2Database
- Oracle
- Microsoft SQL Server
- MySQL
- PostgreSQL
Em nosso exemplo, usaremos o banco de dados MySQL como exemplo.
As seguintes operações são possíveis no Clojure com relação aos bancos de dados.
Conexão de banco de dados
Antes de se conectar a um banco de dados MySQL, certifique-se do seguinte:
Você criou um banco de dados TESTDB.
Você criou uma tabela EMPLOYEE em TESTDB.
Esta tabela contém os campos FIRST_NAME, LAST_NAME, AGE, SEX e INCOME.
O ID do usuário "testuser" e a senha "test123" são definidos para acessar o TESTDB.
Certifique-se de ter baixado o 'arquivo jar mysql' e adicionado o arquivo ao seu classpath.
Você passou pelo tutorial do MySQL para entender os fundamentos do MySQL .
Sintaxe
A seguir está a sintaxe para criar uma conexão no Clojure.
(def connection_name {
:subprotocol “protocol_name”
:subname “Location of mysql DB”
:user “username” :password “password” })
Parameters- 'connection_name' é o nome a ser dado à conexão. 'subprotocol' é o protocolo a ser usado para a conexão. Por padrão, usaremos o protocolo mysql. 'subnome' é o url para conectar ao banco de dados mysql junto com o nome do banco de dados. 'usuário' é o nome de usuário usado para se conectar ao banco de dados. 'senha' é a senha a ser usada para conectar ao banco de dados.
Return Value - Isso fornecerá uma string de conexão, que pode ser usada em operações subsequentes do mysql.
O exemplo a seguir mostra como se conectar às tabelas no esquema de informações e recuperar todos os dados da tabela.
Exemplo
(ns test.core
(:require [clojure.java.jdbc :as sql]))
(defn -main []
(def mysql-db {
:subprotocol "mysql"
:subname "//127.0.0.1:3306/information_schema"
:user "root"
:password "shakinstev"})
(println (sql/query mysql-db
["select table_name from tables"]
:row-fn :table_name)))
Consultando dados
Consultar dados em qualquer banco de dados significa buscar algumas informações úteis do banco de dados. Depois que uma conexão de banco de dados for estabelecida, você estará pronto para fazer uma consulta a esse banco de dados. A seguir está a sintaxe pela qual os dados podem ser consultados usando Clojure.
Sintaxe
clojure.java.jdbc/query dbconn
["query"]
:row-fn :sequence
Parameters- 'dbconn' é o nome da conexão usada para conectar ao banco de dados. 'query' é a string de consulta usada para buscar dados do banco de dados. ': sequência' é, por padrão, todas as linhas de dados buscadas no banco de dados e é retornado como uma sequência. As operações necessárias na sequência podem então ser feitas para ver quais dados foram buscados.
Return Value - Isso retornará uma sequência, que terá as linhas de dados da operação de consulta.
O exemplo a seguir mostra como se conectar à tabela de funcionários e buscar a coluna first_name das linhas da tabela.
Exemplo
(ns test.core
(:require [clojure.java.jdbc :as sql]))
(defn -main []
(def mysql-db {
:subprotocol "mysql"
:subname "//127.0.0.1:3306/testdb"
:user "root"
:password "shakinstev"})
(println (sql/query mysql-db
["select first_name from employee"]
:row-fn :first_name)))
Pelo código acima, podemos ver que
A consulta de “selecionar o nome do funcionário” é passada como string de consulta.
O: first_name é a sequência, que é retornada como resultado da operação de busca.
Se assumirmos que existe apenas uma linha em nosso banco de dados que contém um valor first_name de John, a seguir será a saída do programa acima.
(John)
Inserindo Dados
É necessário quando você deseja criar seus registros em uma tabela de banco de dados. A seguir está a sintaxe pela qual os dados podem ser inseridos usando Clojure. Isso é feito usando o‘insert!’ função.
Sintaxe
clojure.java.jdbc/insert!
:table_name {:column_namen columnvalue}
Parameters- ': table_name' é o nome da tabela em que a inserção deve ser feita. '{: column_namen columnvalue}' é um mapa de todos os nomes e valores de coluna, que precisam ser adicionados como uma linha na tabela.
Return Value - Isso retornará nulo se a inserção for feita com sucesso.
O exemplo a seguir mostra como inserir um registro na tabela de funcionários no banco de dados testdb.
Exemplo
(ns test.core
(:require [clojure.java.jdbc :as sql]))
(defn -main []
(def mysql-db {
:subprotocol "mysql"
:subname "//127.0.0.1:3306/testdb"
:user "root"
:password "shakinstev"})
(sql/insert! mysql-db
:employee {:first_name "John" :last_name "Mark" :sex "M" :age 30 :income 30}))
Se você verificar agora seu banco de dados MySQL e a tabela de funcionários, verá que a linha acima será inserida com êxito na tabela.
Excluindo Dados
As linhas podem ser excluídas de uma tabela usando o ‘delete!’função. A seguir está a sintaxe de como essa operação pode ser executada.
Sintaxe
clojure.java.jdbc/delete!
:table_name [condition]
Parameters- ': table_name' é o nome da tabela em que a inserção deve ser feita. 'condição' é a condição usada para determinar qual linha precisa ser excluída da tabela.
Return Value - Isso retornará o número de linhas excluídas.
O exemplo a seguir mostra como excluir um registro da tabela de funcionários no banco de dados testdb. O exemplo exclui uma linha da tabela com base na condição de que a idade seja igual a 30.
Exemplo
(ns test.core
(:require [clojure.java.jdbc :as sql]))
(defn -main []
(def mysql-db {
:subprotocol "mysql"
:subname "//127.0.0.1:3306/testdb"
:user "root"
:password "shakinstev"})
(println (sql/delete! mysql-db
:employee ["age = ? " 30])))
Se você tinha um registro com uma linha com idade igual ao valor 30, essa linha será excluída.
Atualizando Dados
As linhas podem ser atualizadas de uma tabela usando o ‘update!’função. A seguir está a sintaxe de como essa operação pode ser executada.
Sintaxe
clojure.java.jdbc/update!
:table_name
{setcondition}
[condition]
Parameters- ': table_name' é o nome da tabela em que a inserção deve ser feita. 'setcondition' é a coluna que precisa ser atualizada conforme mencionado em termos de um mapa. 'condição' é a condição que é usada para determinar qual linha precisa ser excluída da tabela.
Return Value - Isso retornará o número de linhas atualizadas.
O exemplo a seguir mostra como excluir um registro da tabela de funcionários no banco de dados testdb. O exemplo atualiza uma linha da tabela com base na condição de que a idade seja igual a 30 e atualiza o valor da renda para 40.
(ns test.core
(:require [clojure.java.jdbc :as sql]))
(defn -main []
(def mysql-db {
:subprotocol "mysql"
:subname "//127.0.0.1:3306/testdb"
:user "root"
:password "shakinstev"})
(println (sql/update! mysql-db
:employee
{:income 40}
["age = ? " 30])))
Se você tivesse um registro com uma linha com idade igual ao valor 30, essa linha será atualizada e o valor da renda será definido para 40.
Transações
As transações são mecanismos que garantem a consistência dos dados. As transações têm as seguintes quatro propriedades -
Atomicity - Ou uma transação é concluída ou nada acontece.
Consistency - Uma transação deve começar em um estado consistente e deixar o sistema em um estado consistente.
Isolation - Os resultados intermediários de uma transação não são visíveis fora da transação atual.
Durability - Depois que uma transação foi confirmada, os efeitos são persistentes, mesmo após uma falha do sistema.
Exemplo
O exemplo a seguir mostra como implementar transações em Clojure. Todas as operações que precisam ser realizadas em uma transação precisam ser incorporadas no‘with-dbtransaction’ cláusula.
(ns test.core
(:require [clojure.java.jdbc :as sql]))
(defn -main []
(def mysql-db {
:subprotocol "mysql"
:subname "//127.0.0.1:3306/testdb"
:user "root"
:password "shakinstev"})
(sql/with-db-transaction [t-con mysql-db]
(sql/update! t-con
:employee
{:income 40}
["age = ? " 30])))
Como já sabemos, o código Clojure é executado no ambiente virtual Java no final. Portanto, só faz sentido que Clojure seja capaz de utilizar todas as funcionalidades do Java. Neste capítulo, vamos discutir a correlação entre Clojure e Java.
Chamando Métodos Java
Os métodos Java podem ser chamados usando a notação de ponto. Um exemplo são strings. Uma vez que todas as strings em Clojure são strings Java, você pode chamar métodos Java normais em strings.
Um exemplo de como isso é feito é mostrado no programa a seguir.
Exemplo
(ns Project
(:gen-class))
(defn Example []
(println (.toUpperCase "Hello World")))
(Example)
O programa acima produz a seguinte saída. Você pode ver no código que, se apenas chamar a notação de ponto para qualquer método de string, ela também funcionará no Clojure.
Resultado
HELLO WORLD
Chamando métodos Java com parâmetros
Você também pode chamar métodos Java com parâmetros. Um exemplo de como isso é feito é mostrado no programa a seguir.
Exemplo
(ns Project
(:gen-class))
(defn Example []
(println (.indexOf "Hello World","e")))
(Example)
O programa acima produz a seguinte saída. Você pode ver pelo código acima, que estamos passando o parâmetro “e” para o método indexOf. O programa acima produz a seguinte saída.
Resultado
1
Criação de objetos Java
Os objetos podem ser criados em Clojure usando a palavra-chave 'novo' semelhante ao que é feito em Java.
Um exemplo de como isso é feito é mostrado no programa a seguir.
Exemplo
(ns Project
(:gen-class))
(defn Example []
(def str1 (new String "Hello"))
(println str1))
(Example)
O programa acima produz a seguinte saída. Você pode ver no código acima, que podemos usar a palavra-chave 'new' para criar um novo objeto da classe String existente do Java. Podemos passar o valor ao criar o objeto, assim como fazemos em Java. O programa acima produz a seguinte saída.
Resultado
Hello
A seguir está outro exemplo que mostra como podemos criar um objeto da classe Integer e usá-lo nos comandos normais do Clojure.
Exemplo
(ns Project
(:gen-class))
(defn Example []
(def my-int(new Integer 1))
(println (+ 2 my-int)))
(Example)
O programa acima produz a seguinte saída.
Resultado
3
Comando de Importação
Também podemos usar o comando import para incluir bibliotecas Java no namespace para que as classes e métodos possam ser acessados facilmente.
O exemplo a seguir mostra como podemos usar o comando import. No exemplo, estamos usando o comando import para importar as classes dojava.util.stackbiblioteca. Podemos então usar o método push e pop da classe stack como eles são.
Exemplo
(ns Project
(:gen-class))
(import java.util.Stack)
(defn Example []
(let [stack (Stack.)]
(.push stack "First Element")
(.push stack "Second Element")
(println (first stack))))
(Example)
O programa acima produz a seguinte saída.
Resultado
First Element
Executando código usando o comando Java
O código Clojure pode ser executado usando o comando Java. A seguir está a sintaxe de como isso pode ser feito.
java -jar clojure-1.2.0.jar -i main.clj
Você deve mencionar o arquivo jar do Clojure, para que todas as classes baseadas em Clojure sejam carregadas no JVM. O arquivo 'main.clj' é o arquivo de código Clojure que precisa ser executado.
Funções Java integradas
Clojure pode usar muitas das funções integradas do Java. Alguns deles são -
Math PI function- Clojure pode usar o método Math para o valor de PI. A seguir está um código de exemplo.
Exemplo
(ns Project
(:gen-class))
(defn Example []
(println (. Math PI)))
(Example)
O código acima produz a seguinte saída.
Resultado
3.141592653589793
System Properties- Clojure também pode consultar as propriedades do sistema. A seguir está um código de exemplo.
Exemplo
(ns Project
(:gen-class))
(defn Example []
(println (.. System getProperties (get "java.version"))))
(Example)
Dependendo da versão do Java no sistema, o valor correspondente será exibido. A seguir está um exemplo de saída.
Resultado
1.8.0_45
Na programação Clojure, a maioria dos tipos de dados são imutáveis, portanto, quando se trata de programação simultânea, o código que usa esses tipos de dados é bastante seguro quando o código é executado em vários processadores. Porém, muitas vezes, há um requisito para compartilhar dados e, quando se trata de dados compartilhados entre vários processadores, é necessário garantir que o estado dos dados seja mantido em termos de integridade ao trabalhar com vários processadores. Isso é conhecido comoconcurrent programming e Clojure fornece suporte para essa programação.
O sistema de memória transacional de software (STM), exposto por meio de dosync, ref, set, alter, etc. suporta o compartilhamento de estado de mudança entre threads de maneira síncrona e coordenada. O sistema do agente suporta o compartilhamento de mudança de estado entre threads de maneira assíncrona e independente. O sistema de átomos suporta o compartilhamento de estado de mudança entre threads de maneira síncrona e independente. Considerando que o sistema var dinâmico, exposto por meio de def, binding, etc. suporta o isolamento de estado de mudança dentro das threads.
Outras linguagens de programação também seguem o modelo de programação simultânea.
Eles têm uma referência direta aos dados que podem ser alterados.
Se o acesso compartilhado for necessário, o objeto será bloqueado, o valor será alterado e o processo continuará para o próximo acesso a esse valor.
Em Clojure não há bloqueios, mas referências indiretas a estruturas de dados persistentes imutáveis.
Existem três tipos de referências em Clojure.
Vars - As mudanças são isoladas em threads.
Refs - As mudanças são sincronizadas e coordenadas entre os threads.
Agents - Envolve mudanças independentes assíncronas entre threads.
As seguintes operações são possíveis no Clojure com relação à programação simultânea.
Transações
A simultaneidade em Clojure é baseada em transações. As referências só podem ser alteradas dentro de uma transação. As seguintes regras são aplicadas nas transações.
- Todas as mudanças são atômicas e isoladas.
- Cada mudança em uma referência acontece em uma transação.
- Nenhuma transação vê o efeito feito por outra transação.
- Todas as transações são colocadas dentro do bloco dosync.
Já vimos o que o bloco dosync faz, vamos examiná-lo novamente.
dosync
Executa a expressão (em um do implícito) em uma transação que abrange a expressão e todas as chamadas aninhadas. Inicia uma transação se nenhuma já estiver em execução neste encadeamento. Qualquer exceção não detectada abortará a transação e sairá do dosync.
A seguir está a sintaxe.
Sintaxe
(dosync expression)
Parameters - 'expressão' é o conjunto de expressões que virão no bloco dosync.
Return Value - Nenhum.
Vejamos um exemplo em que tentamos alterar o valor de uma variável de referência.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def names (ref []))
(alter names conj "Mark"))
(Example)
Resultado
O programa acima, quando executado, apresenta o seguinte erro.
Caused by: java.lang.IllegalStateException: No transaction running
at clojure.lang.LockingTransaction.getEx(LockingTransaction.java:208)
at clojure.lang.Ref.alter(Ref.java:173)
at clojure.core$alter.doInvoke(core.clj:1866)
at clojure.lang.RestFn.invoke(RestFn.java:443)
at clojure.examples.example$Example.invoke(main.clj:5) at clojure.examples.example$eval8.invoke(main.clj:7)
at clojure.lang.Compiler.eval(Compiler.java:5424)
... 12 more
Com o erro, você pode ver claramente que não pode alterar o valor de um tipo de referência sem primeiro iniciar uma transação.
Para que o código acima funcione, temos que colocar o comando alter em um bloco dosync como feito no programa a seguir.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def names (ref []))
(defn change [newname]
(dosync
(alter names conj newname)))
(change "John")
(change "Mark")
(println @names))
(Example)
O programa acima produz a seguinte saída.
Resultado
[John Mark]
Vamos ver outro exemplo de dosync.
Exemplo
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def var1 (ref 10))
(def var2 (ref 20))
(println @var1 @var2)
(defn change-value [var1 var2 newvalue]
(dosync
(alter var1 - newvalue)
(alter var2 + newvalue)))
(change-value var1 var2 20)
(println @var1 @var2))
(Example)
No exemplo acima, temos dois valores que estão sendo alterados em um bloco dosync. Se a transação for bem-sucedida, ambos os valores serão alterados, caso contrário, toda a transação falhará.
O programa acima produz a seguinte saída.
Resultado
10 20
-10 40
Clojure tem algumas bibliotecas contribuídas que têm a capacidade de criar Desktop e Web-based applications. Vamos discutir cada um deles.
Sr. Não. | Aplicativos e descrição |
---|---|
1 | Desktop - gangorra O See-saw é uma biblioteca que pode ser usada para criar aplicativos de desktop. |
2 | Desktop - Mudando o valor do texto O valor do conteúdo na janela pode ser alterado usando o ‘config!’opção. No exemplo a seguir, o config! opção é usada para alterar o conteúdo da janela para o novo valor de “Good Bye”. |
3 | Desktop - Exibindo uma caixa de diálogo modal Uma caixa de diálogo modal pode ser exibida usando o método de alerta da classe gangorra. O método assume o valor do texto, que precisa ser mostrado na caixa de diálogo modal. |
4 | Desktop - Exibindo botões Os botões podem ser exibidos com a ajuda da classe de botões. |
5 | Desktop - Exibindo rótulos Os rótulos podem ser exibidos com a ajuda da classe de rótulos. |
6 | Desktop - Exibindo Campos de Texto Os campos de texto podem ser exibidos com a ajuda da classe de texto. |
Aplicativos da Web - Introdução
Para criar um aplicativo da web em Clojure você precisa usar a biblioteca de aplicativos do Ring, que está disponível no seguinte link https://github.com/ring-clojure/ring
Você precisa certificar-se de baixar os jars necessários do site e adicioná-los como uma dependência para o aplicativo Clojure.
o Ring framework fornece os seguintes recursos -
Configura as coisas de forma que uma solicitação http entre em seu aplicativo da web como um Clojure HashMap regular e, da mesma forma, faz com que você possa retornar uma resposta como um HashMap.
Fornece uma especificação que descreve exatamente como esses mapas de solicitação e resposta devem ser.
Traz um servidor web (Jetty) e conecta seu aplicativo web a ele.
O framework Ring pode iniciar automaticamente um servidor web e garante que o aplicativo Clojure funcione neste servidor. Então também se pode usar a estrutura Compojure. Isso permite criar rotas que agora são a forma como a maioria dos aplicativos da web modernos são desenvolvidos.
Creating your first Clojure application - O exemplo a seguir mostra como você pode criar seu primeiro aplicativo da web no Clojure.
(ns my-webapp.handler
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defroutes app-routes
(GET "/" [] "Hello World")
(route/not-found "Not Found"))
(def app
(wrap-defaults app-routes site-defaults))
Vejamos os seguintes aspectos do programa -
o ‘defroutes’ é usado para criar rotas de forma que a solicitação feita ao aplicativo da web para diferentes rotas possa ser direcionada para diferentes funções em seu aplicativo Clojure.
No exemplo acima, o “/” é conhecido como a rota padrão, portanto, quando você navegar até a base do seu aplicativo da web, a string “Hello World” será enviada ao navegador da web.
Se o usuário acessar qualquer url que não possa ser processada pelo aplicativo Clojure, ele exibirá a string “Não encontrado”.
Ao executar o aplicativo Clojure, por padrão, seu aplicativo será carregado como localhost: 3000, portanto, se você navegar até este local, receberá a seguinte saída.
Aplicativos da Web - Adicionando mais rotas ao seu aplicativo da Web
Você também pode adicionar mais rotas ao seu aplicativo da web. O exemplo a seguir mostra como fazer isso.
(ns my-webapp.handler
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defroutes app-routes
(GET "/" [] "Hello World")
(GET "/Tutorial" [] "This is a tutorial on Clojure")
(route/not-found "Not Found"))
(def app
(wrap-defaults app-routes site-defaults))
Você pode ver que adicionar uma rota no aplicativo é tão fácil quanto adicionar outra função GET com a rota de url. (GET "/ Tutorial" [] "Este é um tutorial sobre Clojure")
Se você navegar até o local http://localhost:3000/Tutorial, você receberá a seguinte saída.
Neste capítulo, vamos discutir as opções de teste automatizado fornecidas pelo Clojure.
Teste de aplicativos cliente
Para usar o teste para o framework Clojure, você deve usar as dependências localizadas em https://github.com/slagyr/speclj#manual-installation
Este URL fornece o specljframework, que é usado como um framework de teste baseado em dados de teste ou baseado em comportamento para Clojure. Você deve garantir o uso da estrutura Clojure 1.7.0 ao usar qualquer uma das bibliotecas 'speclj'. Por padrão, os arquivos de teste serão diferentes dos arquivos de código do Clojure e precisam ser colocados em um diretório 'spec'.
A seguir está um código de amostra para um arquivo de teste.
(ns change.core-spec
(:require [speclj.core :refer :all]))
(describe "Truth"
(it "is true"
(should true))
(it "is not false"
(should-not false)))
(run-specs)
O seguinte deve ser observado sobre o código acima -
Primeiro, temos que garantir o uso da instrução 'require' para incluir todas as bibliotecas centrais na estrutura 'speclj'.
A seguir está a função 'descrever'. Isso é usado para fornecer uma descrição para o caso de teste que está sendo criado.
A próxima função é a função 'it', que é o caso de teste real. No primeiro caso de teste, a string “é verdadeiro” é o nome dado ao caso de teste.
Devem e não devem são conhecidos como assertions. Todas as afirmações começam com deveria. Deveria e não deveria são apenas duas das muitas afirmações disponíveis. Ambos assumem expressões que verificarão quanto à veracidade e falsidade, respectivamente.
Se você executar o caso de teste, obterá a seguinte saída. A saída mostra o tempo gasto em milissegundos para a execução do caso de teste.
←[32m.←[0m←[32m.←[0m
Finished in 0.00014 seconds
Teste de aplicativos baseados na web
Seleniumé uma das principais estruturas usadas para testar aplicativos modernos baseados na web. Bibliotecas Clojure também estão disponíveis, as quais podem ser usadas para testar aplicativos baseados na web.
Vejamos como podemos usar as bibliotecas Selenium para testar aplicativos Clojure baseados na web.
Step 1- A primeira etapa é garantir que estamos usando a estrutura Ring e Compojure para criar um aplicativo baseado na web, que precisa ser testado. Vamos usar um dos exemplos de nossos capítulos anteriores. O código a seguir é um aplicativo da web simples, que exibe “Hello World” no navegador.
(ns my-webapp.handler
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defroutes app-routes
(GET "/" [] "Hello World")
(route/not-found "Not Found"))
(def app
(wrap-defaults app-routes site-defaults))
Step 2 - Em seguida, certifique-se de baixar o arquivo jar de selênio https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server/2.47.0 e inclua-o em seu classpath.
Step 3 - Certifique-se também de baixar o driver da web 'clj', que será usado para executar o teste da web no seguinte local.
https://clojars.org/clj-webdriver/versions/0.7.1
Step 4 - No diretório do seu projeto, crie outro diretório chamado features e crie um arquivo chamado 'config.clj'.
Step 5 - Em seguida, adicione o seguinte código ao arquivo 'config.clj' criado na etapa anterior.
ns clj-webdriver-tutorial.features.config)
(def test-port 3000)
(def test-host "localhost")
(def test-base-url (str "http://" test-host ":" test-port "/"))
O código acima basicamente diz à estrutura de teste da web para testar o aplicativo, que é carregado no URL http://localhost:3000
Step 6 - Por fim, vamos escrever nosso código para realizar nosso teste.
(ns clj-webdriver-tutorial.features.homepage
(:require [clojure.test :refer :all]
[ring.adapter.jetty :refer [run-jetty]]
[clj-webdriver.taxi :refer :all]
[clj-webdriver-tutorial.features.config :refer :all]
[clj-webdriver-tutorial.handler :refer [app-routes]]))
(ns clj-webdriver-tutorial.features.homepage
(:require [clojure.test :refer :all]
[ring.adapter.jetty :refer [run-jetty]]
[clj-webdriver.taxi :refer :all]
[clj-webdriver-tutorial.features.config :refer :all]
[clj-webdriver-tutorial.handler :refer [app-routes]]))
(defn start-server []
(loop [server (run-jetty app-routes {:port test-port, :join? false})]
(if (.isStarted server)
server
(recur server))))
(defn stop-server [server]
(.stop server))
(defn start-browser []
(set-driver! {:browser :firefox}))
(defn stop-browser []
(quit))
(deftest homepage-greeting
(let [server (start-server)]
(start-browser)
(to test-base-url)
(is (= (text "body") "Hello World"))
(stop-browser)
(stop-server server)))
O código acima irá realizar as seguintes ações -
- Inicie o servidor para o aplicativo.
- Abra o caminho raiz no navegador.
- Verifique se a mensagem "Hello World" está presente na página.
- Feche o navegador.
- Desligue o servidor.
Uma coisa que torna a biblioteca Clojure tão poderosa é o número de bibliotecas disponíveis para o framework Clojure. Já vimos muitas bibliotecas usadas em nossos exemplos anteriores para teste da web, desenvolvimento da web, desenvolvimento de aplicativos baseados em swing, a biblioteca jdbc para conexão com bancos de dados MySQL. A seguir estão apenas alguns exemplos de mais algumas bibliotecas.
data.xml
Esta biblioteca permite que Clojure trabalhe com dados XML. A versão da biblioteca a ser usada é org.clojure / data.xml "0.0.8". O data.xml oferece suporte para análise e emissão de XML. As funções de análise lerão XML de um Reader ou InputStream.
Exemplo
A seguir está um exemplo do processamento de dados de uma string para XML.
(ns clojure.examples.example
(use 'clojure.data.xml)
(:gen-class))
(defn Example []
(let [input-xml (java.io.StringReader. "<?xml version = \"1.0\"
encoding = \"UTF-8\"?><example><clo><Tutorial>The Tutorial
value</Tutorial></clo></example>")]
(parse input-xml)))
#clojure.data.xml.Element{
:tag :example, :attrs {}, :content (#clojure.data.xml.Element {
:tag :clo, :attrs {}, :content (#clojure.data.xml.Element {
:tag :Tutorial, :attrs {},:content ("The Tutorial value")})})}
(Example)
data.json
Esta biblioteca permite que Clojure trabalhe com dados JSON. A versão da biblioteca a ser usada é org.clojure / data.json "0.2.6".
Exemplo
A seguir está um exemplo do uso desta biblioteca.
(ns clojure.examples.example
(:require [clojure.data.json :as json])
(:gen-class))
(defn Example []
(println (json/write-str {:a 1 :b 2})))
(Example)
Resultado
O programa acima produz a seguinte saída.
{\"a\":1,\"b\":2}
data.csv
Esta biblioteca permite que Clojure trabalhe com ‘csv’dados. A versão da biblioteca a ser usada é org.clojure / data.csv "0.1.3".
Exemplo
A seguir está um exemplo do uso desta biblioteca.
(ns clojure.examples.example
(require '[clojure.data.csv :as csv]
'[clojure.java.io :as io])
(:gen-class))
(defn Example []
(with-open [in-file (io/reader "in-file.csv")]
(doall
(csv/read-csv in-file)))
(with-open [out-file (io/writer "out-file.csv")]
(csv/write-csv out-file
[[":A" "a"]
[":B" "b"]])))
(Example)
No código acima, a função 'csv' lerá primeiro um arquivo chamado in-file.csve coloque todos os dados na variável no arquivo. Em seguida, estamos usando a função write-csv para gravar todos os dados em um arquivo chamadoout-file.csv.