Clojure - Guida rapida

Clojure è un linguaggio di programmazione funzionale dinamico di alto livello. Clojure è progettato sulla base del linguaggio di programmazione LISP e dispone di compilatori che lo rendono eseguito su ambienti runtime Java e .Net.

Prima di parlare di Clojure, diamo solo una breve descrizione del linguaggio di programmazione LISP. I LISP hanno un minuscolo nucleo del linguaggio, quasi nessuna sintassi e una potente funzione macro. Con queste caratteristiche, puoi piegare LISP per soddisfare il tuo design, invece del contrario. LISP esiste da molto tempo sin dal 1958.

Common LISP legge un'espressione, la valuta e quindi stampa il risultato. Ad esempio, se desideri calcolare il valore di una semplice espressione matematica di 4 + 6, digita.

USER(1) (+ 4 6)

Clojure ha i seguenti obiettivi chiave di alto livello come linguaggio di programmazione.

  • Si basa sul linguaggio di programmazione LISP che rende le sue istruzioni in codice più piccole dei linguaggi di programmazione tradizionali.

  • È un linguaggio di programmazione funzionale.

  • Si concentra sull'immutabilità che è fondamentalmente il concetto che non dovresti apportare modifiche agli oggetti che vengono creati sul posto.

  • Può gestire lo stato di un'applicazione per il programmatore.

  • Supporta la concorrenza.

  • Comprende i linguaggi di programmazione esistenti. Ad esempio, Clojure può sfruttare l'intero ecosistema Java per la gestione dell'esecuzione del codice tramite JVM.

Il sito ufficiale di Clojure è https://clojure.org/

Ci sono molti modi per lavorare con Clojure come linguaggio di programmazione. Vedremo due modi per lavorare con la programmazione Clojure.

  • Leiningen - Leiningen è uno strumento essenziale per creare, costruire e automatizzare i progetti Clojure.

  • Eclipse Plugin - Esiste un plugin chiamato CounterClockwise, disponibile per Eclipse per lo sviluppo di Clojure nell'IDE Eclipse.

Installazione di Leiningen

Assicurarsi che i seguenti requisiti di sistema siano soddisfatti prima di procedere con l'installazione.

Requisiti di sistema

JDK JDK 1.7 o successivo
Memoria 2 GB di RAM (consigliato)

Step 1- Scarica l'installazione binaria. Vai al collegamentohttp://leiningen-wininstallerper ottenere Windows Installer. Fare clic sull'opzione per avviare il download del programma di installazione di Groovy.

Step 2 - Avvia il programma di installazione e fai clic sul pulsante Avanti.

Step 3 - Specificare la posizione per l'installazione e fare clic sul pulsante Avanti.

Step 4- La configurazione rileverà la posizione di un'installazione Java esistente. Fare clic sul pulsante Avanti per procedere.

Step 5 - Fare clic sul pulsante Installa per avviare l'installazione.

Al termine dell'installazione, ti darà la possibilità di aprire un Clojure REPL, che è un ambiente che può essere utilizzato per creare e testare i tuoi programmi Clojure.

Installazione di Eclipse

Assicurarsi che i seguenti requisiti di sistema siano soddisfatti prima di procedere con l'installazione.

Requisiti di sistema

JDK JDK 1.7 o successivo
Eclisse Eclipse 4.5 (Marte)

Step 1- Apri Eclipse e fai clic sulla voce Menu. Fare clic su Guida → Eclipse Marketplace.

Step 2- Digita la parola chiave Clojure nella finestra di dialogo che appare e premi il pulsante "Vai". Apparirà l'opzione per il senso antiorario, fare clic sul pulsante Installa per avviare l'installazione di questo plugin.

Step 3 - Nella finestra di dialogo successiva, fare clic sul pulsante Conferma per avviare l'installazione.

Step 4- Nella finestra di dialogo successiva, ti verrà chiesto di accettare il contratto di licenza. Accetta il contratto di licenza e fai clic sul pulsante Fine per continuare con l'installazione.

L'installazione inizierà e, una volta completata, ti verrà chiesto di riavviare Eclipse.

Una volta riavviato Eclipse, vedrai l'opzione in Eclipse per creare un nuovo progetto Clojure.

Per comprendere la sintassi di base di Clojure, diamo prima un'occhiata a un semplice programma Hello World.

Hello World come programma completo

Scrivi "Hello world" in un programma Clojure completo. Di seguito è riportato un esempio.

Esempio

(ns clojure.examples.hello
   (:gen-class))
(defn hello-world []
   (println "Hello World"))
(hello-world)

Le seguenti cose devono essere annotate sul programma di cui sopra.

  • Il programma verrà scritto in un file chiamato main.clj. L'estensione "clj" è il nome dell'estensione per un file di codice clojure. Nell'esempio sopra, il nome del file si chiama main.clj.

  • La parola chiave "defn" viene utilizzata per definire una funzione. Vedremo le funzioni in dettaglio in un altro capitolo. Ma per ora, sappi che stiamo creando una funzione chiamata helloworld, che avrà il nostro codice Clojure principale.

  • Nel nostro codice Clojure, stiamo usando l'istruzione 'println' per stampare "Hello World" nell'output della console.

  • Chiamiamo quindi la funzione hello-world che a sua volta esegue l'istruzione "println".

Il programma precedente produce il seguente output.

Produzione

Hello World

Forma generale di una dichiarazione

La forma generale di qualsiasi istruzione deve essere valutata tra parentesi graffe come mostrato nell'esempio seguente.

(+ 1 2)

Nell'esempio precedente, l'intera espressione è racchiusa tra parentesi graffe. L'output dell'istruzione precedente è 3. L'operatore + si comporta come una funzione in Clojure, che viene utilizzata per l'aggiunta di numeri. I valori di 1 e 2 sono noti come parameters to the function.

Consideriamo un altro esempio. In questo esempio, "str" ​​è l'operatore utilizzato per concatenare due stringhe. Le stringhe "Hello" e "World" vengono utilizzate come parametri.

(str "Hello" "World")

Esempio

Se combiniamo le due affermazioni precedenti e scriviamo un programma, apparirà come segue.

(ns clojure.examples.hello
   (:gen-class))
(defn Example []
   (println (str "Hello World"))
   (println (+ 1 2)))
(Example)

Produzione

Il programma precedente produce il seguente output.

Hello World
3

Spazi dei nomi

Uno spazio dei nomi viene utilizzato per definire un confine logico tra i moduli definiti in Clojure.

Spazio dei nomi corrente

Questo definisce lo spazio dei nomi corrente in cui risiede il codice Clojure corrente.

Sintassi

*ns*

Esempio

Nella finestra di comando REPL eseguire il seguente comando.

*ns*

Produzione

Quando eseguiamo il comando precedente, l'output differirà a seconda di quale sia lo spazio dei nomi corrente. Di seguito è riportato un esempio di output. Lo spazio dei nomi del codice Clojure è -

clojure.examples.hello

(ns clojure.examples.hello
   (:gen-class))
(defn Example []
   (println (str "Hello World"))
   (println (+ 1 2)))
(Example)

Richiedi dichiarazione in Clojure

Il codice Clojure è confezionato in librerie. Ogni libreria Clojure appartiene a uno spazio dei nomi, che è analogo a un pacchetto Java. Puoi caricare una libreria Clojure con l'istruzione "Require".

Sintassi

(require quoted-namespace-symbol)

Esempio

Di seguito è riportato un esempio di utilizzo di questa dichiarazione.

(ns clojure.examples.hello
   (:gen-class))
(require ‘clojure.java.io’)
(defn Example []
   (.exists (file "Example.txt")))
(Example)

Nel codice sopra, stiamo usando la parola chiave 'require' per importare lo spazio dei nomi clojure.java.io che ha tutte le funzioni richieste per la funzionalità di input / output. Poiché non abbiamo la libreria richiesta, possiamo usare la funzione 'file' nel codice sopra.

Commenti in Clojure

I commenti vengono utilizzati per documentare il codice. I commenti a riga singola vengono identificati utilizzando il ;; in qualsiasi posizione della linea. Di seguito è riportato un esempio.

Esempio

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println "Hello World"))
(Example)

Delimitatori

In Clojure, le dichiarazioni possono essere divise o delimitate utilizzando le parentesi graffe curve o quadre.

Esempio

Di seguito sono riportati due esempi.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println (+ 1 2 3)))
(Example)

Produzione

Il programma precedente produce il seguente output.

6

Esempio

Di seguito è riportato un altro esempio.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println [+ 1 2 3]))
(Example)

Produzione

Il programma precedente produce il seguente output.

[#object[clojure.core$_PLUS_ 0x10f163b "clojure.core$_PLUS_@10f163b"] 1 2 3]

Spazi bianchi

Gli spazi bianchi possono essere utilizzati in Clojure per dividere diversi componenti di un'istruzione per una migliore chiarezza. Questo può essere fatto con l'assistenza dell'operatore virgola (,).

Ad esempio, le due istruzioni seguenti sono equivalenti e l'output di entrambe le istruzioni sarà 15.

(+ 1 2 3 4 5)
(+ 1, 2, 3, 4, 5)

Sebbene Clojure ignori le virgole, a volte le usa per rendere le cose più facili da leggere per il programmatore.

Ad esempio, se hai una mappa hash come la seguente (def a-map {: a 1: b 2: c 3}) e chiedi il suo valore nella finestra REPL, Clojure stamperà l'output come {: a 1, : b 2,: c 3}.

I risultati sono più facili da leggere, soprattutto se stai esaminando una grande quantità di dati.

Simboli

In Clojure, i simboli sono equivalenti agli identificatori in altri linguaggi di programmazione. Ma a differenza di altri linguaggi di programmazione, il compilatore vede i simboli come valori stringa effettivi. Poiché un simbolo è un valore, un simbolo può essere memorizzato in una raccolta, passato come argomento a una funzione, ecc., Proprio come qualsiasi altro oggetto.

Un simbolo può contenere solo caratteri alfanumerici e '* +! /. : - _? ' ma non deve iniziare con un numero o due punti.

Di seguito sono riportati validi esempi di simboli.

tutorial-point!
TUTORIAL
+tutorial+

Struttura del progetto Clojure

Infine parliamo di una tipica struttura di progetto per un progetto Clojure. Poiché il codice Clojure viene eseguito su Java virtual machine, la maggior parte della struttura del progetto all'interno di Clojure è simile a quella che si troverebbe in un progetto java. Di seguito è riportata l'istantanea di una struttura di progetto di esempio in Eclipse per un progetto Clojure.

Le seguenti cose fondamentali devono essere annotate sulla struttura del programma di cui sopra.

  • demo_1 - Questo è il pacchetto in cui viene inserito il file di codice Clojure.

  • core.clj - Questo è il file di codice Clojure principale, che conterrà il codice per l'applicazione Clojure.

  • La cartella Leiningen contiene file come clojure-1.6.0.jar, necessario per eseguire qualsiasi applicazione basata su Clojure.

  • Il file pom.properties conterrà informazioni come groupId, artifactId e la versione del progetto Clojure.

  • Il file project.clj contiene informazioni sull'applicazione Clojure stessa. Di seguito è riportato un esempio del contenuto del file di progetto.

(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 (read-eval-print loop) è uno strumento per sperimentare con il codice Clojure. Ti consente di interagire con un programma in esecuzione e di provare rapidamente se le cose funzionano come dovrebbero. Lo fa presentandoti un prompt in cui puoi inserire il codice. Quindi legge il tuo input, lo valuta, stampa il risultato e ripete il ciclo, presentandoti di nuovo un prompt.

Questo processo consente un rapido ciclo di feedback che non è possibile nella maggior parte delle altre lingue.

Avvio di una sessione REPL

Una sessione REPL può essere avviata a Leiningen digitando il seguente comando nella riga di comando.

lein repl

Questo avvierà la seguente finestra REPL.

Quindi inizi a valutare i comandi Clojure nella finestra REPL come richiesto.

Per avviare una sessione REPL in Eclipse, fare clic sull'opzione Menu, andare su Esegui come → Applicazione Clojure.

Questo avvierà una nuova sessione REPL in una finestra separata insieme all'output della console.

Concettualmente, REPL è simile a Secure Shell (SSH). Allo stesso modo in cui puoi utilizzare SSH per interagire con un server remoto, Clojure REPL ti consente di interagire con un processo Clojure in esecuzione. Questa funzione può essere molto potente perché puoi persino allegare un REPL a un'app di produzione live e modificare il tuo programma mentre viene eseguito.

Variabili speciali in REPL

REPL include alcune variabili utili, quella ampiamente utilizzata è la variabile speciale * 1, * 2 e * 3. Questi vengono utilizzati per valutare i risultati delle tre espressioni più recenti.

L'esempio seguente mostra come queste variabili possono essere utilizzate.

user => "Hello"
Hello
user => "World"
World
user => (str *2 *1)
HelloWorld

Nell'esempio precedente, le prime due stringhe vengono inviate alla finestra di output REPL rispettivamente come "Hello" e "World". Quindi le variabili * 2 e * 1 vengono utilizzate per richiamare le ultime 2 espressioni valutate.

Clojure offre un'ampia varietà di built-in data types.

Tipi di dati incorporati

Di seguito è riportato un elenco di tipi di dati definiti in Clojure.

  • Integers - Di seguito sono riportate le rappresentazioni di numeri interi disponibili in Clojure.

    • Decimal Integers (Short, Long and Int)- Questi sono usati per rappresentare numeri interi. Ad esempio, 1234.

    • Octal Numbers- Questi sono usati per rappresentare i numeri nella rappresentazione ottale. Ad esempio, 012.

    • Hexadecimal Numbers- Questi sono usati per rappresentare i numeri nella rappresentazione. Ad esempio, 0xff.

    • Radix Numbers- Questi sono usati per rappresentare i numeri nella rappresentazione della radice. Ad esempio, 2r1111 dove la radice è un numero intero compreso tra 2 e 36, inclusi.

  • Floating point

    • L'impostazione predefinita viene utilizzata per rappresentare i numeri in virgola mobile a 32 bit. Ad esempio, 12.34.

    • L'altra rappresentazione è la notazione scientifica. Ad esempio, 1.35e-12.

  • char- Questo definisce un singolo carattere letterale. I caratteri sono definiti con il simbolo del backlash. Ad esempio, / e.

  • Boolean - Questo rappresenta un valore booleano, che può essere vero o falso.

  • String- Questi sono letterali di testo che sono rappresentati sotto forma di catena di caratteri. Ad esempio, "Hello World".

  • Nil - Questo è usato per rappresentare un valore NULL in Clojure.

  • Atom- Gli atomi forniscono un modo per gestire lo stato condiviso, sincrono e indipendente. Sono un tipo di riferimento come refs e vars.

Valori vincolati

Poiché tutti i tipi di dati in Clojure vengono ereditati da Java, i valori limitati sono gli stessi del linguaggio di programmazione Java. La tabella seguente mostra i valori massimi consentiti per i valori letterali numerici e decimali.

letterali Intervalli
Corto Da -32.768 a 32.767
int -2.147.483.648 a 2.147.483.647
lungo -9.223.372.036.854.775.808 a +9.223.372.036.854.775.807
galleggiante Da 1,40129846432481707e-45 a 3,40282346638528860e + 38
Doppio 4.94065645841246544e-324d a 1.79769313486231570e + 308d

Tipi numerici di classe

Oltre ai tipi primitivi, sono consentiti i seguenti tipi di oggetto (a volte indicati come tipi wrapper).

Nome
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double

Esempio

Il seguente programma mostra un codice clojure consolidato per dimostrare i tipi di dati in 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)

Produzione

Il programma precedente produce il seguente output.

1
1.25
Hello

A Clojure, variables sono definiti dal ‘def’parola chiave. È un po 'diverso in cui il concetto di variabili ha più a che fare con l'associazione. In Clojure, un valore è associato a una variabile. Una cosa fondamentale da notare in Clojure è che le variabili sono immutabili, il che significa che affinché il valore della variabile cambi, deve essere distrutto e ricreato di nuovo.

Di seguito sono riportati i tipi base di variabili in Clojure.

  • short- Viene utilizzato per rappresentare un numero breve. Ad esempio, 10.

  • int- Viene utilizzato per rappresentare numeri interi. Ad esempio, 1234.

  • long- Viene utilizzato per rappresentare un numero lungo. Ad esempio, 10000090.

  • float- Viene utilizzato per rappresentare i numeri in virgola mobile a 32 bit. Ad esempio, 12.34.

  • char- Questo definisce un singolo carattere letterale. Ad esempio, "/ a".

  • Boolean - Questo rappresenta un valore booleano, che può essere vero o falso.

  • String- Questi sono letterali di testo che sono rappresentati sotto forma di catena di caratteri. Ad esempio, "Hello World".

Dichiarazioni di variabili

Di seguito è riportata la sintassi generale per definire una variabile.

Sintassi

(def var-name var-value)

Dove 'var-name' è il nome della variabile e 'var-value' è il valore associato alla variabile.

Esempio

Di seguito è riportato un esempio di dichiarazione di variabili.

(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)

Denominazione delle variabili

Il nome di una variabile può essere composto da lettere, cifre e il carattere di sottolineatura. Deve iniziare con una lettera o un trattino basso. Le lettere maiuscole e minuscole sono distinte perché Clojure, proprio come Java, è un linguaggio di programmazione che fa distinzione tra maiuscole e minuscole.

Esempio

Di seguito sono riportati alcuni esempi di denominazione di variabili in 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 - Nelle dichiarazioni precedenti, a causa della distinzione tra maiuscole e minuscole, status e STATUS sono due diverse variabili definite in Clojure.

L'esempio sopra mostra come definire una variabile con un carattere di sottolineatura.

Stampa di variabili

Poiché Clojure utilizza l'ambiente JVM, puoi anche utilizzare la funzione "println". Il seguente esempio mostra come questo può essere ottenuto.

Esempio

(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)

Produzione

Il programma precedente produce il seguente output.

1
1.25
Hello

Un operator è un simbolo che dice al compilatore di eseguire specifiche manipolazioni matematiche o logiche.

Clojure ha i seguenti tipi di operatori:

  • Operatori aritmetici
  • Operatori relazionali
  • Operatori logici
  • Operatori bit per bit

Note - In Clojure, gli operatori e gli operandi funzionano nella seguente sintassi.

Sintassi

(operator operand1 operand2 operandn)

Per esempio,

Esempio

(+ 1 2)

L'esempio precedente esegue un'operazione aritmetica sui numeri 1 e 2.

Operatori aritmetici

Il linguaggio Clojure supporta i normali operatori aritmetici come qualsiasi linguaggio. Di seguito sono riportati gli operatori aritmetici disponibili in Clojure.

Mostra esempi

Operatore Descrizione Esempio
+ Aggiunta di due operandi (+ 1 2) darà 3
- Sottrae il secondo operando dal primo (- 2 1) darà 1
* Moltiplicazione di entrambi gli operandi (* 2 2) darà 4
/ Divisione del numeratore per denominatore (float (/ 3 2)) restituirà 1.5
inc Operatori incrementali utilizzati per incrementare il valore di un operando di 1 inc 5 darà 6
dec Operatori incrementali utilizzati per decrementare il valore di un operando di 1 5 dicembre darà 4
max Restituisce il più grande dei suoi argomenti max 1 2 3 restituirà 3
min Restituisce il più piccolo dei suoi argomenti min 1 2 3 restituirà 1
rem Resto della divisione del primo numero per il secondo rem 3 2 darà 1

Operatori relazionali

Gli operatori relazionali consentono il confronto degli oggetti. Di seguito sono riportati gli operatori relazionali disponibili in Clojure.

Mostra esempi

Operatore Descrizione Esempio
= Verifica l'uguaglianza tra due oggetti (= 2 2) darà vero
non = Verifica la differenza tra due oggetti (non = 3 2) darà vero
< Verifica se l'oggetto sinistro è minore dell'operando destro (<2 3) darà vero
<= Verifica se l'oggetto sinistro è minore o uguale all'operando destro (<= 2 3) darà vero
> Verifica se l'oggetto sinistro è maggiore dell'operando destro (> 3 2) darà vero
> = Controlla se l'oggetto sinistro è maggiore o uguale all'operando destro (> = 3 2) darà vero

Operatori logici

Gli operatori logici vengono utilizzati per valutare le espressioni booleane. Di seguito sono riportati gli operatori logici disponibili in Groovy.

Mostra esempi

Operatore Descrizione Esempio
and Questo è l'operatore logico "and" (o vero vero) darà vero
or Questo è l'operatore logico "or" (e vero falso) darà falso
not Questo è l'operatore logico "non" (non falso) darà vero

Il seguente frammento di codice mostra come possono essere utilizzati i vari operatori.

Operatori bit per bit

Clojure fornisce quattro operatori bit per bit. Di seguito sono riportati gli operatori bit per bit disponibili in Clojure.

Mostra esempi

Sr.No. Operatore e descrizione
1

bit-and

Questo è l'operatore "and" bit per bit

2

bit-or

Questo è l'operatore "or" bit per bit

3

bit-xor

Questo è l'operatore "xor" o esclusivo "or" bit per bit

4

bit-not

Questo è l'operatore di negazione bit per bit

Di seguito è riportata la tabella della verità che mostra questi operatori.

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

Precedenza operatore

Come nel caso dei LISP in generale, non è necessario preoccuparsi della precedenza degli operatori. Questo è uno dei vantaggi delle espressioni S e della notazione dei prefissi. Tutte le funzioni valutano da sinistra a destra e al contrario. Gli operatori in Clojure sono solo funzioni e tutto è completamente tra parentesi.

Finora abbiamo visto istruzioni che vengono eseguite una dopo l'altra in modo sequenziale. Inoltre, in Clojure vengono fornite istruzioni per alterare il flusso di controllo nella logica di un programma. Vengono quindi classificati in dichiarazioni di flusso di controllo che vedremo in dettaglio.

Sr.No. Loop e descrizione
1 Dichiarazione While

Il 'while' viene eseguita valutando prima l'espressione della condizione (un valore booleano) e, se il risultato è vero, vengono eseguite le istruzioni nel ciclo while.

2 Dichiarazione Doseq

Il ‘doseq’è simile all'istruzione "for each" che si trova in molti altri linguaggi di programmazione. L'istruzione doseq è fondamentalmente utilizzata per iterare su una sequenza.

3 Dichiarazione Dotimes

Il ‘dotimes’ istruzione viene utilizzata per eseguire un'istruzione "x" un numero di volte.

4 Istruzione Loop

La forma speciale del ciclo non è come un file ‘for’ciclo continuo. L'utilizzo di loop è lo stesso dell'associazione let. Tuttavia, loop imposta un punto di ricorsione

Decision-making structures richiedere che il programmatore specifichi una o più condizioni che devono essere valutate o testate dal programma, insieme a una o più istruzioni da eseguire se la condizione è determinata essere vera e, facoltativamente, altre istruzioni da eseguire se la condizione è determinata a essere falso.

Sr.No. Metodi e descrizione
1 Istruzione If

In Clojure, la condizione è un'espressione che la valuta come vera o falsa. 'If' la condizione è vera, quindi verrà eseguita l'istruzione # 1, altrimenti verrà eseguita l'istruzione # 2.

2 If / do Expression

Il ‘if-do’ espressione in Clojure viene utilizzata per consentire l'esecuzione di più espressioni per ogni ramo dell'istruzione "if".

3 Istruzione If annidata

Molteplici 'if' dichiarazioni incorporate l'una nell'altra.

4 Dichiarazione del caso

Clojure offre il ‘case’ dichiarazione che è simile a ‘switch’ istruzione disponibile nel linguaggio di programmazione Java.

5 Dichiarazione Cond

Clojure offre un'altra dichiarazione di valutazione chiamata ‘cond’dichiarazione. Questa istruzione accetta un insieme di coppie test / espressione.

Clojure è noto come linguaggio di programmazione funzionale, quindi ti aspetteresti di vedere molta enfasi su come funzionano le funzioni in Clojure. Questo capitolo descrive cosa si può fare con le funzioni in Clojure.

Sr.No. Funzioni e descrizione
1 Definizione di una funzione

Una funzione viene definita utilizzando il ‘defn’ macro.

2 Funzioni anonime

Una funzione anonima è una funzione a cui non è associato alcun nome.

3 Funzioni con più argomenti

Le funzioni clojure possono essere definite con zero o più parametri. I valori passati alle funzioni vengono chiamatiargumentse gli argomenti possono essere di qualsiasi tipo.

4 Funzioni variadiche

Clojure offre l'istruzione "case" che è simile all'istruzione "switch" disponibile nel linguaggio di programmazione Java.

5 Funzioni di ordine superiore

Le funzioni di ordine superiore (HOF) sono funzioni che accettano altre funzioni come argomenti. Gli HOF sono un'importante tecnica di programmazione funzionale e sono abbastanza comunemente usati in Clojure.

Numbers il tipo di dati in Clojure è derivato dalle classi Java.

Clojure supporta numeri interi e in virgola mobile.

  • Un numero intero è un valore che non include una frazione.

  • Un numero a virgola mobile è un valore decimale che include una frazione decimale.

Di seguito è riportato un esempio di numeri in Clojure.

(def x 5)
(def y 5.25)

Dove "x" è del tipo Integer e "y" è il file float.

In Java, le seguenti classi sono associate ai numeri definiti in Clojure.

Per vedere effettivamente che i numeri in Clojure derivano da classi Java, utilizzare il seguente programma per vedere il tipo di numeri assegnati quando si utilizza il comando "def".

Esempio

(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)

Il ‘type’ viene utilizzato per visualizzare la classe associata al valore assegnato a una variabile.

Produzione

Il codice precedente produrrà il seguente output.

Java.lang.long
Java.lang.double

Test numerici

Le seguenti funzioni di test sono disponibili per i numeri.

Sr.No. Numeri e descrizione
1 zero?

Restituisce vero se il numero è zero, altrimenti falso.

2 pos?

Restituisce vero se numero è maggiore di zero, altrimenti falso.

3 neg?

Restituisce vero se numero è minore di zero, altrimenti falso.

4 anche?

Restituisce vero se il numero è pari e genera un'eccezione se il numero non è un numero intero.

5 dispari?

Restituisce vero se il numero è dispari e genera un'eccezione se il numero non è un numero intero.

6 numero?

Restituisce vero se il numero è realmente un numero.

7 numero intero?

Restituisce vero se il numero è un numero intero.

8 galleggiante?

Restituisce vero se il numero è un float.

Abbiamo visto l'istruzione recur in un argomento precedente e mentre il ciclo "for" è un po 'come un ciclo, recur è un vero e proprio loop in Clojure.

Se hai un background di programmazione, potresti aver sentito parlare della ricorsione in coda, che è una delle principali caratteristiche dei linguaggi funzionali. Questa forma speciale ricorre è quella che implementa la ricorsione della coda. Come indica la parola "ricorsione della coda", la ricorsione deve essere chiamata nella posizione della coda. In altre parole, la ricorrenza deve essere l'ultima cosa da valutare.

L'esempio più semplice dell'istruzione recur viene utilizzato all'interno del ciclo "for". Nell'esempio seguente, l'istruzione recur viene utilizzata per modificare il valore della variabile "i" e restituire il valore della variabile all'espressione del ciclo.

Esempio

(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)

Produzione

Il programma precedente produce il seguente output.

0
1
2
3
4

Clojure fornisce una serie di metodi di supporto quando si lavora con l'I / O. Offre classi più semplici per fornire le seguenti funzionalità per i file.

  • Lettura di file
  • Scrittura su file
  • Verificare se un file è un file o una directory

Esploriamo alcune delle operazioni sui file che Clojure ha da offrire.

Lettura del contenuto di un file come un'intera stringa

Se vuoi ottenere l'intero contenuto del file come una stringa, puoi usare l'estensione clojure.core.slurpmetodo. Il comando slurp apre un lettore su un file e ne legge tutto il contenuto, restituendo una stringa.

Di seguito è riportato un esempio di come questo può essere fatto.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (def string1 (slurp "Example.txt"))
   (println string1))
(Example)

Se il file contiene le seguenti righe, verranno stampate come:

line : Example1
line : Example2

Leggere il contenuto di un file una riga alla volta

Se vuoi ottenere l'intero contenuto del file come una stringa una riga alla volta, puoi usare il clojure.java.io/readermetodo. La classe clojure.java.io/reader crea un buffer di lettura, che viene utilizzato per leggere ogni riga del file.

Di seguito è riportato un esempio che mostra come eseguire questa operazione.

(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)

Se il file contiene le seguenti righe, verranno stampate come:

line : Example1
line : Example2

L'output verrà mostrato come -

["line : Example1" "line : Example2"]

Scrittura "in" file

Se vuoi scrivere "su" file, puoi usare l'estensione clojure.core.spitcomando per sputare intere stringhe in file. Il comando spit è l'opposto del metodo slurp. Questo metodo apre un file come scrittore, scrive il contenuto, quindi chiude il file.

Di seguito è riportato un esempio.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (spit "Example.txt"
      "This is a string"))

Nell'esempio precedente, se vedi il contenuto del file Example.txt, vedrai il contenuto di "Questa è una stringa".

Scrivere file "su" una riga alla volta

Se vuoi scrivere "su" file una riga alla volta, puoi usare il clojure.java.io.writerclasse. La classe clojure.java.io.writer viene utilizzata per creare un flusso di scrittura in cui i byte di dati vengono inseriti nel flusso e successivamente nel file.

Di seguito è riportato un esempio che mostra come utilizzare il comando spit.

(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)

Quando viene eseguito il codice precedente, la riga "hello world" sarà presente nel file Example.txt. L'opzione append: true consiste nell'aggiungere dati al file. Se questa opzione non è specificata, il file verrà sovrascritto ogni volta che i dati vengono scritti nel file.

Controllo per vedere se esiste un file

Per verificare se esiste un file, il clojure.java.io.fileclass può essere utilizzato per verificare l'esistenza di un file. Di seguito è riportato un esempio che mostra come questo può essere realizzato.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println (.exists (clojure.java.io/file "Example.txt"))))
(Example)

Se il file Example.txt esiste, l'output sarà vero.

Lettura dalla console

Per leggere i dati dalla console, il read-linedichiarazione può essere utilizzata. Di seguito è riportato un esempio che mostra come questo può essere utilizzato.

Se inserisci il comando (read-line) nella finestra REPL, avrai la possibilità di inserire qualche input nella finestra della console.

user->(read-line)
Hello World

Il codice precedente produrrà il seguente output.

“Hello World”

UN Stringletterale è costruito in Clojure racchiudendo il testo della stringa tra virgolette. Le stringhe in Clojure devono essere costruite utilizzando le virgolette doppie come "Hello World".

Esempio

Di seguito è riportato un esempio dell'utilizzo delle stringhe in Clojure.

(ns clojure.examples.hello
   (:gen-class))
(defn hello-world []
   (println "Hello World")
   (println "This is a demo application"))
(hello-world)

Produzione

Il programma precedente produce il seguente output.

Hello World
This is a demo application

Operazioni di base sulle stringhe

Clojure ha una serie di operazioni che possono essere eseguite sulle stringhe. Di seguito sono riportate le operazioni.

Sr.No. Operazioni su stringhe e descrizione
1 str

La concatenazione di stringhe può essere eseguita dalla semplice funzione str.

2 formato

La formattazione delle stringhe può essere eseguita dalla semplice funzione di formattazione. La funzione format formatta una stringa usandojava.lang.String.format.

3 contare

Restituisce il numero di caratteri nella stringa.

4 sottotitoli

Restituisce la sottostringa di "s" che inizia all'inizio compreso e termina alla fine (il valore predefinito è la lunghezza della stringa), esclusa.

5 confrontare

Restituisce un numero negativo, zero o un numero positivo quando "x" è logicamente "minore di", "uguale a" o "maggiore di" "y".

6 minuscolo

Converte la stringa in tutte le lettere minuscole.

7 maiuscolo

Converte la stringa in tutte le lettere maiuscole.

8 aderire

Restituisce una stringa di tutti gli elementi nella raccolta, come restituito da (raccolta seq), separati da un separatore opzionale.

9 Diviso

Divide la stringa in un'espressione regolare.

10 linee di divisione

Le stringhe divise si basano sui caratteri di escape \ n o \ r \ n.

11 inversione

Inverte i caratteri in una stringa.

12 sostituire

Sostituisce tutte le istanze di una corrispondenza in una stringa con la stringa di sostituzione.

13 trim

Rimuove gli spazi da entrambe le estremità della stringa.

14 triml

Rimuove gli spazi bianchi dal lato sinistro della stringa.

15 trimr

Rimuove gli spazi bianchi dal lato destro della stringa.

Listè una struttura utilizzata per memorizzare una raccolta di elementi di dati. In Clojure, l'elenco implementa ilISeqinterfaccia. Gli elenchi vengono creati in Clojure utilizzando la funzione elenco.

Esempio

Di seguito è riportato un esempio di creazione di un elenco di numeri in Clojure.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (println (list 1 2 3 4)))
(example)

Produzione

Il codice precedente produce il seguente output.

(1 2 3 4)

Di seguito è riportato un esempio di creazione di un elenco di personaggi in Clojure.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (println (list 'a 'b 'c 'd)))
(example)

Il codice precedente produce il seguente output.

(a b c d)

Di seguito sono riportati i metodi di elenco disponibili in Clojure.

Sr.No. Elenchi e descrizione
1 elenco*

Crea un nuovo elenco contenente gli elementi anteposti al resto, l'ultimo dei quali verrà trattato come una sequenza.

2 primo

Questa funzione restituisce il primo elemento nell'elenco.

3 ennesimo

Questa funzione restituisce l'elemento nella posizione "n-esima" nell'elenco.

4 contro

Restituisce un nuovo elenco in cui un elemento viene aggiunto all'inizio dell'elenco.

5 conj

Restituisce un nuovo elenco in cui l'elenco è all'inizio e gli elementi da aggiungere sono posti alla fine.

6 riposo

Restituisce gli elementi rimanenti nell'elenco dopo il primo elemento.

Setsin Clojure sono un insieme di valori unici. I set vengono creati in Clojure con l'aiuto del comando set.

Esempio

Di seguito è riportato un esempio della creazione di set in Clojure.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (println (set '(1 1 2 2))))
(example)

Produzione

Il codice precedente produce il seguente output.

#{1,2}

Di seguito sono riportati i metodi disponibili in Clojure per i set.

Sr.No. Set e descrizione
1 set ordinato

Restituisce un insieme ordinato di elementi.

2 ottenere

Restituisce l'elemento nella posizione dell'indice.

3 contiene?

Scopri se il set contiene un determinato elemento o meno.

4 conj

Aggiunge un elemento all'insieme e restituisce il nuovo insieme di elementi.

5 disj

Separa un elemento dall'insieme.

6 unione

Restituisce un set che è l'unione dei set di input

7 differenza

Restituisce un set che è il primo set senza elementi dei set rimanenti.

8 intersezione

Restituisce un insieme che è l'intersezione degli insiemi di input.

9 sottoinsieme?

Set1 è un sottoinsieme di set2?

10 superset?

Set1 è un superset di set2?

UN Vectorè una raccolta di valori indicizzati da interi contigui. Un vettore viene creato utilizzando il metodo vettoriale in Clojure.

Esempio

Di seguito è riportato un esempio di creazione di un vettore in Clojure.

(ns clojure.examples.example
   (:require [clojure.set :as set])
   (:gen-class))
(defn example []
   (println (vector 1 2 3)))
(example)

Produzione

Il codice precedente produce il seguente output.

[1 2 3]

Di seguito sono riportati i metodi disponibili in Clojure.

Sr.No. Vettori e descrizione
1 vettore di

Crea un nuovo vettore di un singolo tipo primitivo 't', dove 't' è uno tra: int: long: float: double: byte: short: char o: boolean.

2 ennesimo

Questa funzione restituisce l'elemento all'ennesima posizione nel vettore.

3 ottenere

Restituisce l'elemento nella posizione di indice nel vettore.

4 conj

Aggiunge un elemento al vettore e restituisce il nuovo set di elementi vettoriali.

5 pop

Per un elenco o una coda, restituisce un nuovo elenco / coda senza il primo elemento, per un vettore, restituisce un nuovo vettore senza l'ultimo elemento.

6 subvec

Restituisce un vettore secondario da un indice iniziale e uno finale.

UN Mapè una raccolta che associa le chiavi ai valori. Sono disponibili due diversi tipi di mappe: hash e ordinate.HashMaps richiedono chiavi che supportino correttamente hashCode ed è uguale a. SortedMaps richiedono chiavi che implementino Comparable o un'istanza di Comparator.

Una mappa può essere creata in due modi, il primo è tramite il metodo hash-map.

Creazione - HashMaps

Le hashmap hanno una tipica relazione valore-chiave e vengono create utilizzando la funzione hash-map.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (def demokeys (hash-map "z" "1" "b" "2" "a" "3"))
   (println demokeys))
(example)

Produzione

Il codice precedente produce il seguente output.

{z 1, b 2, a 3}

Creazione - SortedMaps

SortedMaps ha la caratteristica unica di ordinare i propri elementi in base all'elemento chiave. Di seguito è riportato un esempio che mostra come creare la mappa ordinata utilizzando la funzione mappa ordinata.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (def demokeys (sorted-map "z" "1" "b" "2" "a" "3"))
   (println demokeys))
(example)

Il codice precedente produce il seguente output.

{a 3, b 2, z 1}

Dal programma di cui sopra puoi vedere chiaramente che gli elementi nelle mappe sono ordinati in base al valore della chiave. Di seguito sono riportati i metodi disponibili per le mappe.

Sr.No. Mappe e descrizione
1 ottenere

Restituisce il valore mappato su key, not-found o nil se key non è presente.

2 contiene?

Verifica se la mappa contiene una chiave richiesta.

3 trova

Restituisce la voce della mappa per la chiave.

4 chiavi

Restituisce l'elenco delle chiavi nella mappa.

5 vals

Restituisce l'elenco dei valori nella mappa.

6 dissoc

Dissocia una voce di valore chiave dalla mappa.

7 unire

Unisce due voci di mappa in una singola voce di mappa.

8 fondersi con

Restituisce una mappa che consiste nel resto delle mappe riunite nella prima.

9 tasti di selezione

Restituisce una mappa contenente solo le voci nella mappa la cui chiave è in keys.

10 rinomina-chiavi

Rinomina le chiavi nella HashMap corrente con quelle appena definite.

11 map-invert

Inverte le mappe in modo che i valori diventino le chiavi e viceversa.

Namespacesin Clojure vengono utilizzati per differenziare le classi in spazi logici separati proprio come in Java. Considera la seguente dichiarazione.

(:require [clojure.set :as set])

Nell'istruzione precedente, "clojure.set" è uno spazio dei nomi che contiene varie classi e metodi da utilizzare nel programma. Ad esempio, lo spazio dei nomi sopra contiene la funzione chiamata map-invert, che viene utilizzata per invertire una mappa di valori-chiave. Non possiamo usare questa funzione a meno che non diciamo esplicitamente al nostro programma di includere questo spazio dei nomi.

Diamo un'occhiata ai diversi metodi disponibili per gli spazi dei nomi.

Sr.No. Metodi e descrizione
1 * ns *

Viene utilizzato per esaminare il tuo spazio dei nomi corrente.

2 ns

Viene utilizzato per creare un nuovo spazio dei nomi e associarlo al programma in esecuzione.

3 alias

Aggiungi un alias nello spazio dei nomi corrente a un altro spazio dei nomi. Gli argomenti sono due simboli: l'alias da utilizzare e il nome simbolico dello spazio dei nomi di destinazione.

4 all-ns

Restituisce un elenco di tutti gli spazi dei nomi.

5 find-ns

Trova e restituisce un particolare spazio dei nomi.

6 ns-name

Restituisce il nome di un particolare spazio dei nomi.

7 ns-alias

Restituisce gli alias, che sono associati a qualsiasi spazio dei nomi.

8 ns-map

Restituisce una mappa di tutte le mappature per lo spazio dei nomi.

9 un-alias

Restituisce una mappa contenente solo le voci nella mappa la cui chiave è in keys.

Exception handlingè richiesto in qualsiasi linguaggio di programmazione per gestire gli errori di runtime in modo che il normale flusso dell'applicazione possa essere mantenuto. L'eccezione di solito interrompe il normale flusso dell'applicazione, motivo per cui è necessario utilizzare la gestione delle eccezioni nella nostra applicazione.

L'eccezione è ampiamente classificata nelle seguenti categorie:

  • Checked Exception- Le classi che estendono la classe Throwable eccetto RuntimeException ed Error sono note come eccezioni controllate. Ad esempio IOException, SQLException, ecc. Le eccezioni verificate vengono verificate in fase di compilazione.

Consideriamo il seguente programma che esegue un'operazione su un file chiamato Example.txt. Tuttavia, può sempre esserci un caso in cui il file Example.txt non esiste.

(ns clojure.examples.example
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (def string1 (slurp "Example.txt"))
   (println string1))
(Example)

Se il file Example.txt non esiste, la seguente eccezione verrà generata dal programma.

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)

Dall'eccezione precedente, possiamo vedere chiaramente che il programma ha generato un'eccezione FileNotFoundException.

  • Unchecked Exception- Le classi che estendono RuntimeException sono note come eccezioni non controllate. Ad esempio, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, ecc. Le eccezioni deselezionate non vengono verificate in fase di compilazione, piuttosto vengono controllate in fase di esecuzione.

Un caso classico è ArrayIndexOutOfBoundsException che si verifica quando si tenta di accedere a un indice di un array che è maggiore della lunghezza dell'array. Di seguito è riportato un tipico esempio di questo tipo di errore.

(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 viene eseguito il codice precedente, verrà sollevata la seguente eccezione.

caught exception: java.lang.ArrayIndexOutOfBoundsException: 5
This is our final block
Let's move on

Errore

L'errore è irrecuperabile, ad esempio OutOfMemoryError, VirtualMachineError, AssertionError, ecc. Ora abbiamo bisogno di un meccanismo per catturare queste eccezioni in modo che il programma possa continuare a funzionare se queste eccezioni esistono.

Il diagramma seguente mostra come è organizzata la gerarchia delle eccezioni in Clojure. È tutto basato sulla gerarchia definita in Java.

Catturare le eccezioni

Proprio come altri linguaggi di programmazione, Clojure fornisce il normale blocco "try-catch" per catturare le eccezioni come e quando si verificano.

Di seguito è riportata la sintassi generale del blocco try-catch.

(try
   (//Protected code)
   catch Exception e1)
(//Catch block)

Tutto il codice che potrebbe sollevare un'eccezione viene inserito nel file Protected code block.

Nel catch block, puoi scrivere codice personalizzato per gestire l'eccezione in modo che l'applicazione possa eseguire il ripristino dall'eccezione.

Diamo un'occhiata al nostro esempio precedente che ha generato un'eccezione file non trovato e vediamo come possiamo usare il blocco try catch per catturare l'eccezione sollevata dal programma.

(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)

Il programma precedente produce il seguente output.

caught exception: Example.txt (No such file or directory)

Dal codice sopra, escludiamo il codice difettoso nel file try block. Nel blocco catch, stiamo solo catturando la nostra eccezione e inviando un messaggio che si è verificata un'eccezione. Quindi, ora abbiamo un modo significativo per catturare l'eccezione, che viene generata dal programma.

Blocchi multipli di cattura

Si possono avere più blocchi catch per gestire più tipi di eccezioni. Per ogni blocco catch, a seconda del tipo di eccezione sollevata, dovresti scrivere codice per gestirlo di conseguenza.

Modifichiamo il nostro codice precedente per includere due blocchi catch, uno specifico per l'eccezione file non trovato e l'altro per un blocco eccezione generale.

(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)

Il programma precedente produce il seguente output.

caught file exception: Example.txt (No such file or directory)
Let's move on

Dall'output di cui sopra, possiamo vedere chiaramente che la nostra eccezione è stata catturata dal blocco catch "FileNotFoundException" e non da quello generale.

Infine Block

Il blocco finalmente segue un blocco try o un blocco catch. Un blocco di codice infine viene sempre eseguito, indipendentemente dal verificarsi di un'eccezione.

L'utilizzo di un blocco finalmente consente di eseguire qualsiasi istruzione di tipo cleanup che si desidera eseguire, indipendentemente da ciò che accade nel codice protetto. Di seguito è riportata la sintassi per questo blocco.

(try
   (//Protected code)
   catch Exception e1)
(//Catch block)
(finally
   //Cleanup code)

Modifichiamo il codice sopra e aggiungiamo il blocco di codice finalmente. Di seguito è riportato lo snippet di codice.

(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)

Il programma precedente produce il seguente output.

caught file exception: Example.txt (No such file or directory)
This is our final block
Let's move on

Dal programma sopra, puoi vedere che il blocco finale viene implementato anche dopo che il blocco catch ha rilevato l'eccezione richiesta.

Poiché Clojure deriva la sua gestione delle eccezioni da Java, in modo simile a Java, i seguenti metodi sono disponibili in Clojure per la gestione delle eccezioni.

  • public String getMessage()- Restituisce un messaggio dettagliato sull'eccezione che si è verificata. Questo messaggio viene inizializzato nel costruttore Throwable.

  • public Throwable getCause() - Restituisce la causa dell'eccezione rappresentata da un oggetto Throwable.

  • public String toString() - Restituisce il nome della classe concatenata con il risultato di getMessage ().

  • public void printStackTrace() - Stampa il risultato di toString () insieme alla traccia dello stack su System.err, il flusso di output dell'errore.

  • public StackTraceElement [] getStackTrace()- Restituisce un array contenente ogni elemento nella traccia dello stack. L'elemento all'indice 0 rappresenta la parte superiore dello stack di chiamate e l'ultimo elemento dell'array rappresenta il metodo in fondo allo stack di chiamate.

  • public Throwable fillInStackTrace() - Riempie la traccia dello stack di questo oggetto Throwable con la traccia dello stack corrente, aggiungendo a qualsiasi informazione precedente nella traccia dello stack.

Di seguito è riportato il codice di esempio che utilizza alcuni dei metodi sopra elencati.

(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)

Il programma precedente produce il seguente output.

caught file exception: java.io.FileNotFoundException: Example.txt (No such file
or directory)
This is our final block
Let's move on

Sequences vengono creati con l'aiuto di ‘seq’comando. Di seguito è riportato un semplice esempio di creazione di una sequenza.

(ns clojure.examples.example
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println (seq [1 2 3])))
(Example)

Il programma precedente produce il seguente output.

(1 2 3)

Di seguito sono riportati i vari metodi disponibili per le sequenze.

Sr.No. Metodi e descrizione
1 contro

Restituisce una nuova sequenza in cui "x" è il primo elemento e "seq" è il resto.

2 conj

Restituisce una nuova sequenza in cui "x" è l'elemento che viene aggiunto alla fine della sequenza.

3 concat

Viene utilizzato per concatenare due sequenze insieme.

4 distinto

Utilizzato solo per garantire che alla sequenza vengano aggiunti elementi distinti.

5 inversione

Inverte gli elementi nella sequenza.

6 primo

Restituisce il primo elemento della sequenza.

7 scorso

Restituisce l'ultimo elemento della sequenza.

8 riposo

Restituisce l'intera sequenza tranne il primo elemento.

9 ordinare

Restituisce una sequenza ordinata di elementi.

10 far cadere

Elimina elementi da una sequenza in base al numero di elementi, che deve essere rimosso.

11 prendere l'ultimo

Prende l'ultimo elenco di elementi dalla sequenza.

12 prendere

Prende il primo elenco di elementi dalla sequenza.

13 diviso in due

Divide la sequenza di elementi in due parti. Viene specificata una posizione in cui deve avvenire la divisione.

UN regular expressionè un modello utilizzato per trovare sottostringhe nel testo. Le espressioni regolari sono utilizzate in una varietà di linguaggi di programmazione e molto utilizzate nei linguaggi di programmazione di tipo LISP.

Di seguito è riportato un esempio di un'espressione regolare.

//d+

L'espressione regolare sopra viene utilizzata per trovare un'ulteriore occorrenza di una cifra in una stringa. I caratteri // vengono utilizzati per garantire che i caratteri "d" e "+" siano utilizzati per rappresentare un'espressione regolare.

In generale, le espressioni regolari funzionano con il seguente insieme di regole.

  • Esistono due caratteri posizionali speciali utilizzati per indicare l'inizio e la fine di una riga: caret (∧) e segno di dollaro ($):

  • Le espressioni regolari possono includere anche quantificatori. Il segno più (+) rappresenta una o più volte, applicato all'elemento precedente dell'espressione. L'asterisco (*) viene utilizzato per rappresentare zero o più occorrenze. Il punto interrogativo (?) Indica zero o una volta.

  • Il metacarattere {e} viene utilizzato per abbinare un numero specifico di istanze del carattere precedente.

  • In un'espressione regolare, il simbolo del punto (.) Può rappresentare qualsiasi carattere. Questo è descritto come il carattere jolly.

  • Un'espressione regolare può includere classi di caratteri. Un insieme di caratteri può essere dato come una semplice sequenza di caratteri racchiusi nei metacaratteri [e] come in [aeiou]. Per intervalli di lettere o numeri, è possibile utilizzare un separatore di trattini come in [a – z] o [a – mA – M]. Il complemento di una classe di caratteri è indicato da un accento circonflesso all'interno delle parentesi quadre come in [∧a – z] e rappresenta tutti i caratteri diversi da quelli specificati.

I seguenti metodi sono disponibili per le espressioni regolari.

Sr.No. Metodi e descrizione
1 ri-modello

Restituisce un'istanza di java.util.regex.Pattern. Questo viene quindi utilizzato in ulteriori metodi per la corrispondenza dei modelli.

2 Ritrovato

Restituisce la successiva corrispondenza regex, se presente, di stringa a pattern, utilizzando java.util.regex.Matcher.find ()

3 sostituire

La funzione di sostituzione viene utilizzata per sostituire una sottostringa in una stringa con un nuovo valore di stringa. La ricerca della sottostringa viene eseguita utilizzando un pattern.

4 sostituire prima

La funzione di sostituzione viene utilizzata per sostituire una sottostringa in una stringa con un nuovo valore di stringa, ma solo per la prima occorrenza della sottostringa. La ricerca della sottostringa viene eseguita utilizzando un pattern.

Predicatessono funzioni che valutano una condizione e forniscono un valore vero o falso. Abbiamo visto funzioni predicative negli esempi del capitolo sui numeri. Abbiamo visto funzioni come "anche?" che viene utilizzato per verificare se un numero è pari o no, o "neg?" che viene utilizzato per verificare se un numero è maggiore di zero o meno. Tutte queste funzioni restituiscono un valore vero o falso.

Di seguito è riportato un esempio di predicati in 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)

Il programma precedente produce il seguente output.

true
false
true
true

Oltre alle normali funzioni dei predicati, Clojure fornisce più funzioni per i predicati. I metodi seguenti sono disponibili per i predicati.

Sr.No. Metodi e descrizione
1 ogni predatore

Accetta un insieme di predicati e restituisce una funzione 'f' che restituisce true se tutti i suoi predicati che la compongono restituiscono un valore logico vero rispetto a tutti i suoi argomenti, altrimenti restituisce false.

2 ogni?

Restituisce vero se il predicato è vero per ogni valore, altrimenti falso.

3 alcuni

Restituisce il primo valore vero logico per qualsiasi valore di predicato x nella raccolta di valori.

4 nemmeno uno?

Restituisce falso se uno qualsiasi dei predicati dei valori in una raccolta è logicamente vero, altrimenti vero.

Destructuring è una funzionalità all'interno di Clojure, che consente di estrarre valori da una struttura di dati, come un vettore e di legarli a simboli senza dover attraversare esplicitamente la struttura di dati.

Diamo un'occhiata a un esempio di cosa significa esattamente Destructuring e di come avviene.

Esempio

(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)

Il programma precedente produce il seguente output.

Produzione

1 2 3 4

Nell'esempio sopra, devono essere annotate le seguenti cose:

  • Stiamo definendo un vettore di numeri interi come 1, 2, 3 e 4.

  • Stiamo quindi utilizzando il ‘let’ per assegnare direttamente 4 variabili (a, b, c e d) alla variabile my-vector.

  • Se eseguiamo il file ‘println’ dichiarazione sulle quattro variabili, possiamo vedere che sono già state assegnate rispettivamente ai valori nel vettore.

Quindi clojure ha destrutturato la variabile my-vector che ha quattro valori quando è stata assegnata usando l'istruzione 'let'. I quattro valori decostruiti sono stati quindi assegnati ai quattro parametri di conseguenza.

Se ci sono variabili in eccesso che non hanno un valore corrispondente a cui possono essere assegnate, verrà assegnato loro il valore nil. L'esempio seguente chiarisce questo punto.

Esempio

(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)

Il programma precedente produce il seguente output. Puoi vedere dall'output che poiché l'ultima variabile 'e' non ha un valore corrispondente nel vettore, è pari a zero.

Produzione

1 2 3 4 nil

il riposo

La variabile "the-rest" viene utilizzata per memorizzare i valori rimanenti, che non possono essere assegnati a nessuna variabile.

Un esempio di come viene utilizzato è mostrato nel seguente programma.

Esempio

(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)

Il programma precedente produce il seguente output. Dall'output, puoi vedere chiaramente che i valori di 3 e 4 non possono essere assegnati a nessuna variabile, quindi sono assegnati alla variabile "the-rest".

Produzione

1 2 (3 4)

Mappe destrutturanti

Proprio come i vettori, anche le mappe possono essere destrutturate. Di seguito è riportato un esempio di come ciò può essere realizzato.

Esempio

(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)

Il programma precedente produce il seguente output. Dal programma è possibile vedere chiaramente che i valori della mappa di “a” e “b” sono assegnati alle variabili di a e b.

Produzione

1 2

Allo stesso modo nel caso dei vettori, se non c'è un valore corrispondente nella mappa quando avviene la destrutturazione, alla variabile verrà assegnato un valore nil.

Di seguito è riportato un esempio.

Esempio

(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)

Il programma precedente produce il seguente output.

Produzione

1 2 nil

Poiché il framework Clojure è derivato dalle classi Java, è possibile utilizzare le classi data-ora disponibili in Java in Clojure. Ilclass date rappresenta uno specifico istante di tempo, con precisione al millisecondo.

Di seguito sono riportati i metodi disponibili per la classe data-ora.

java.util.Date

Viene utilizzato per creare l'oggetto data in Clojure.

Sintassi

Di seguito è riportata la sintassi.

java.util.Date.

Parameters - Nessuno.

Return Value - Alloca un oggetto Date e lo inizializza in modo che rappresenti l'ora in cui è stato allocato, misurato al millisecondo più vicino.

Esempio

Un esempio di come viene utilizzato è mostrato nel seguente programma.

(ns example)
(defn Example []
   (def date (.toString (java.util.Date.)))
   (println date))
(Example)

Produzione

Il programma precedente produce il seguente output. Ciò dipenderà dalla data e dall'ora correnti del sistema su cui viene eseguito il programma.

Tue Mar 01 06:11:17 UTC 2016

java.text.SimpleDateFormat

Viene utilizzato per formattare l'output della data.

Sintassi

Di seguito è riportata la sintassi.

(java.text.SimpleDateFormat. format dt)

Parameters- "formato" è il formato da utilizzare per la formattazione della data. "dt" è la data che deve essere formattata.

Return Value - Un output di data formattato.

Esempio

Un esempio di come viene utilizzato è mostrato nel seguente programma.

(ns example)
(defn Example []
   (def date (.format (java.text.SimpleDateFormat. "MM/dd/yyyy") (new java.util.Date)))
   (println date))
(Example)

Produzione

Il programma precedente produce il seguente output. Ciò dipenderà dalla data e dall'ora correnti del sistema su cui viene eseguito il programma.

03/01/2016

prendi tempo

Restituisce il numero di millisecondi dall'1 gennaio 1970, 00:00:00 GMT rappresentato da questo oggetto Date.

Sintassi

Di seguito è riportata la sintassi.

(.getTime)

Parameters - Nessuno.

Return Value - Il numero di millisecondi dal 1 gennaio 1970, 00:00:00 GMT rappresentato da questa data.

Esempio

Un esempio di come viene utilizzato è mostrato nel seguente programma.

(ns example)
(import java.util.Date)
(defn Example []
   (def date (.getTime (java.util.Date.)))
   (println date))
(Example)

Produzione

Il programma precedente produce il seguente output. Ciò dipenderà dalla data e dall'ora correnti del sistema su cui viene eseguito il programma.

1456812778160

Atomssono un tipo di dati in Clojure che fornisce un modo per gestire lo stato condiviso, sincrono e indipendente. Un atomo è proprio come qualsiasi tipo di riferimento in qualsiasi altro linguaggio di programmazione. L'uso principale di un atomo è quello di contenere le strutture dati immutabili di Clojure. Il valore detenuto da un atomo viene modificato con ilswap! method.

Internamente, scambia! legge il valore corrente, gli applica la funzione e tenta di confrontarlo e impostarlo. Poiché un altro thread potrebbe aver modificato il valore nel tempo intercorso, potrebbe essere necessario riprovare e lo fa in un ciclo di rotazione. L'effetto netto è che il valore sarà sempre il risultato dell'applicazione della funzione fornita a un valore corrente, atomicamente.

Esempio

Gli atomi vengono creati con l'aiuto del metodo atom. Un esempio sullo stesso è mostrato nel seguente programma.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (def myatom (atom 1))
   (println @myatom))
(example)

Produzione

Il programma precedente produce il seguente risultato.

1

Si accede al valore di atom utilizzando il simbolo @. Clojure ha alcune operazioni che possono essere eseguite sugli atomi. Di seguito sono riportate le operazioni.

Sr.No. Operazioni e descrizione
1 Ripristina!

Imposta il valore di atom su un nuovo valore senza considerare il valore corrente.

2 confronta e imposta!

Atomicamente imposta il valore di atom al nuovo valore se e solo se il valore corrente dell'atomo è identico al vecchio valore detenuto dall'atomo. Restituisce true se viene impostato, altrimenti restituisce false.

3 scambiare!

Sostituisce atomicamente il valore dell'atomo con uno nuovo basato su una particolare funzione.

A Clojure, metadataviene utilizzato per annotare i dati in una raccolta o per i dati memorizzati in un simbolo. Questo è normalmente utilizzato per annotare i dati sui tipi nel compilatore sottostante, ma può essere utilizzato anche per gli sviluppatori. I metadati non sono considerati parte del valore dell'oggetto. Allo stesso tempo, i metadati sono immutabili.

Le seguenti operazioni sono possibili in Clojure per quanto riguarda i metadati.

Sr.No. Operazioni e descrizione
1 meta-con

Questa funzione viene utilizzata per definire una mappa di metadati per qualsiasi oggetto.

2 meta

Questa funzione viene utilizzata per vedere se dei metadati sono associati a un oggetto.

3 variare-meta

Restituisce un oggetto dello stesso tipo e valore dell'oggetto originale, ma con metadati combinati.

StructMapssono usati per creare strutture in Clojure. Ad esempio, se si desidera creare una struttura composta da un nome dipendente e un ID dipendente, è possibile farlo con StructMaps.

Le seguenti operazioni sono possibili in Clojure per quanto riguarda StructMaps.

Sr.No. Operazioni e descrizione
1 defstruct

Questa funzione viene utilizzata per definire la struttura richiesta.

2 struct

Questa funzione viene utilizzata per definire un oggetto struttura del tipo, che viene creato dall'operazione defstruct.

3 struct-map

Questa funzione viene utilizzata per assegnare specificamente valori ai valori chiave definendo esplicitamente quali valori vengono assegnati a quali chiavi nella struttura.

4 Accesso ai singoli campi

È possibile accedere ai singoli campi della struttura accedendo alle chiavi insieme all'oggetto struttura.

5 Natura immutabile

Per impostazione predefinita, anche le strutture sono immutabili, quindi se proviamo a modificare il valore di una chiave particolare, non cambierà.

6 Aggiunta di una nuova chiave alla struttura

Poiché le strutture sono immutabili, l'unico modo per aggiungere un'altra chiave alla struttura è tramite la creazione di una nuova struttura. Un esempio di come questo può essere ottenuto è mostrato nel seguente programma.

Come sottolineato molte volte, Clojure è un linguaggio di programmazione in cui molti dei tipi di dati sono immutabili, il che significa che l'unico modo in cui è possibile modificare il valore di una variabile è creare una nuova variabile e assegnarle il nuovo valore. Tuttavia, Clojure fornisce alcuni elementi che possono creare uno stato mutevole. Abbiamo visto che questo può essere ottenuto con il tipo di dati atom. L'altro modo in cui questo può essere ottenuto è tramite agenti.

Agentsfornire modifiche indipendenti e asincrone delle singole posizioni. Gli agenti sono vincolati a una singola posizione di archiviazione per la loro durata e consentono solo la mutazione di quella posizione (in un nuovo stato) come risultato di un'azione. Le azioni sono funzioni (con, facoltativamente, argomenti aggiuntivi) che vengono applicate in modo asincrono allo stato di un agente e il cui valore di ritorno diventa il nuovo stato dell'agente.

Le seguenti operazioni sono possibili in Clojure per quanto riguarda gli agenti.

Sr.No. Operazioni e descrizione
1 agente

Un agente viene creato utilizzando il comando agente.

2 Spedire

Questa funzione viene utilizzata per inviare un valore all'agente.

3 agenti di arresto

Questa funzione viene utilizzata per arrestare qualsiasi agente in esecuzione.

4 commiato

Ci sono casi in cui a un agente viene assegnata una funzione di natura bloccante.

5 attendono

Poiché c'è un ritardo quando un valore di un agente viene aggiornato, Clojure ha fornito una funzione di "attesa per" che viene utilizzata per specificare il tempo in millisecondi di attesa per l'aggiornamento dell'agente.

6 attendere

Blocca il thread corrente (indefinitamente!) Finché tutte le azioni inviate fino a quel momento, da questo thread o agente, agli agenti non si sono verificate. Blocca sugli agenti falliti.

7 errore-agente

Restituisce l'eccezione generata durante un'azione asincrona dell'agente, se l'agente non riesce. Restituisce zero se l'agente non fallisce.

Watcherssono funzioni aggiunte a tipi di variabili come atomi e variabili di riferimento che vengono richiamate quando un valore del tipo di variabile cambia. Ad esempio, se il programma chiamante cambia il valore di una variabile atom e se una funzione watcher è collegata alla variabile atom, la funzione verrà richiamata non appena il valore dell'atomo viene modificato.

Le seguenti funzioni sono disponibili in Clojure for Watchers.

add-watch

Aggiunge una funzione di controllo a un riferimento agent / atom / var / ref. L'orologio‘fn’deve essere una 'fn' di 4 argomenti: una chiave, il riferimento, il suo vecchio stato, il suo nuovo stato. Ogni volta che lo stato del riferimento potrebbe essere stato modificato, tutti gli orologi registrati avranno le loro funzioni chiamate.

Sintassi

Di seguito è riportata la sintassi.

(add-watch variable :watcher
   (fn [key variable-type old-state new-state]))

Parameters- "variabile" è il nome dell'atomo o della variabile di riferimento. 'variabile-tipo' è il tipo di variabile, atom o variabile di riferimento. "vecchio stato e nuovo stato" sono parametri che manterranno automaticamente il vecchio e il nuovo valore della variabile. "key" deve essere univoco per riferimento e può essere utilizzato per rimuovere l'orologio con remove-watch.

Return Value - Nessuno.

Esempio

Un esempio di come viene utilizzato è mostrato nel seguente programma.

(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)

Produzione

Il programma precedente produce il seguente output.

The value of the atom has been changed
old-state 0
new-state 2

rimuovere-guardare

Rimuove un orologio che è stato collegato a una variabile di riferimento.

Sintassi

Di seguito è riportata la sintassi.

(remove-watch variable watchname)

Parameters- "variabile" è il nome dell'atomo o della variabile di riferimento. "watchname" è il nome dato all'orologio quando viene definita la funzione dell'orologio.

Return Value - Nessuno.

Esempio

Un esempio di come viene utilizzato è mostrato nel seguente programma.

(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)

Produzione

Il programma precedente produce il seguente output.

The value of the atom has been changed
old-state 0
new-state 2

Puoi vedere chiaramente dal programma sopra che il secondo comando di ripristino non attiva il watcher poiché è stato rimosso dall'elenco dei watcher.

In qualsiasi lingua, Macrosvengono utilizzati per generare codice in linea. Clojure non fa eccezione e fornisce semplici funzionalità macro per gli sviluppatori. Le macro vengono utilizzate per scrivere routine di generazione del codice, che forniscono allo sviluppatore un modo potente per adattare il linguaggio alle esigenze dello sviluppatore.

Di seguito sono riportati i metodi disponibili per le macro.

defmacro

Questa funzione viene utilizzata per definire la macro. La macro avrà un nome macro, un elenco di parametri e il corpo della macro.

Sintassi

Di seguito è riportata la sintassi.

(defmacro name [params*] body)

Parameters- "nome" è il nome della macro. 'params' sono i parametri assegnati alla macro. "body" è il corpo della macro.

Return Value - Nessuno.

Esempio

Un esempio di come viene utilizzato è mostrato nel seguente programma.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (defmacro Simple []
      (println "Hello"))
   (macroexpand '(Simple)))
(Example)

Produzione

Il programma precedente produce il seguente output.

Hello

Dal programma sopra puoi vedere che la macro 'Simple' è espansa inline a 'println' “Hello”. Le macro sono simili alle funzioni, con la sola differenza che gli argomenti di un modulo vengono valutati nel caso delle macro.

macro-espandere

Viene utilizzato per espandere una macro e inserire il codice inline nel programma.

Sintassi

Di seguito è riportata la sintassi.

(macroexpand macroname)

Parameters - "macroname" è il nome della macro che deve essere espansa.

Return Value - La macro espansa.

Esempio

Un esempio di come viene utilizzato è mostrato nel seguente programma.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (defmacro Simple []
      (println "Hello"))
   (macroexpand '(Simple)))
(Example)

Produzione

Il programma precedente produce il seguente output.

Hello

Macro con argomenti

Le macro possono essere utilizzate anche per accettare argomenti. La macro può contenere un numero qualsiasi di argomenti. L'esempio seguente mostra come utilizzare gli argomenti.

Esempio

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (defmacro Simple [arg]
      (list 2 arg))
   (println (macroexpand '(Simple 2))))
(Example)

L'esempio precedente inserisce un argomento nella macro Semplice e quindi utilizza l'argomento per aggiungere il valore dell'argomento a un elenco.

Produzione

Il programma precedente produce il seguente output.

(2 2)

Reference valuessono un altro modo in cui Clojure può lavorare con la richiesta di avere variabili mutabili. Clojure fornisce tipi di dati modificabili come atomi, agenti e tipi di riferimento.

Di seguito sono riportate le operazioni disponibili per i valori di riferimento.

Sr.No. Operazioni e descrizione
1 rif

Viene utilizzato per creare un valore di riferimento. Quando si crea un valore di riferimento, è disponibile un'opzione per fornire una funzione di convalida, che convaliderà il valore creato.

2 rif-set

Questa funzione viene utilizzata per impostare il valore di un riferimento a un nuovo valore indipendentemente dal valore precedente.

3 alterare

Questa funzione viene utilizzata per modificare il valore di un tipo di riferimento ma in modo sicuro. Viene eseguito in un thread, a cui non è possibile accedere da un altro processo.

4 dosync

Esegue l'espressione (in un do implicito) in una transazione che comprende l'espressione e tutte le chiamate annidate.

5 pendolarismo

Commute viene utilizzato anche per modificare il valore di un tipo di riferimento proprio come alter e ref-set.

Per utilizzare la funzionalità del database, assicurati di scaricare prima il file jdbc files dal seguente url - https://codeload.github.com/clojure/java.jdbc/zip/master

Troverai un file zip che ha i driver necessari per Clojure per avere la possibilità di connettersi ai database. Una volta che il file zip è stato estratto, assicurati di aggiungere la posizione decompressa al tuo classpath.

Il file principale per la connettività del database è un file chiamato jdbc.clj nella posizione clojure / java.

Il connettore clojure jdbc supporta un'ampia varietà di database, alcuni dei quali sono i seguenti.

  • H2Database
  • Oracle
  • Microsoft SQL Server
  • MySQL
  • PostgreSQL

Nel nostro esempio, useremo MySQL DB come esempio.

Le seguenti operazioni sono possibili in Clojure per quanto riguarda i database.

Connessione al database

Prima di connetterti a un database MySQL, assicurati di quanto segue:

  • Hai creato un database TESTDB.

  • Hai creato una tabella EMPLOYEE in TESTDB.

  • Questa tabella ha i campi FIRST_NAME, LAST_NAME, AGE, SEX e INCOME.

  • L'ID utente "testuser" e la password "test123" sono impostati per accedere a TESTDB.

  • Assicurati di aver scaricato il "file jar mysql" e di aver aggiunto il file al tuo classpath.

  • Hai seguito il tutorial di MySQL per comprendere le basi di MySQL .

Sintassi

La seguente è la sintassi per creare una connessione in Clojure.

(def connection_name {
   :subprotocol “protocol_name”
   :subname “Location of mysql DB”
   :user “username” :password “password” })

Parameters- "connection_name" è il nome da assegnare alla connessione. "subprotocol" è il protocollo da utilizzare per la connessione. Per impostazione predefinita utilizzeremo il protocollo mysql. 'subname' è l'URL per connettersi al database mysql insieme al nome del database. "utente" è il nome utente utilizzato per connettersi al database. 'password' è la password da utilizzare per connettersi al database.

Return Value - Questo fornirà una stringa di connessione, che può essere utilizzata nelle successive operazioni mysql.

Il seguente esempio mostra come connettersi alle tabelle nello schema delle informazioni e recuperare tutti i dati nella tabella.

Esempio

(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)))

Interrogazione dei dati

Interrogare i dati su qualsiasi database significa recuperare alcune informazioni utili dal database. Una volta stabilita una connessione al database, sei pronto per eseguire una query in questo database. Di seguito è riportata la sintassi con cui è possibile eseguire query sui dati utilizzando Clojure.

Sintassi

clojure.java.jdbc/query dbconn
["query"]
   :row-fn :sequence

Parameters- "dbconn" è il nome della connessione utilizzata per connettersi al database. "query" è la stringa di query utilizzata per recuperare i dati dal database. ': sequenza' è per impostazione predefinita tutte le righe di dati recuperate dal database e viene restituito come una sequenza. Le operazioni necessarie sulla sequenza possono quindi essere eseguite per vedere quali dati sono stati recuperati.

Return Value - Questo restituirà una sequenza, che avrà le righe di dati dall'operazione di query.

Il seguente esempio mostra come connettersi alla tabella dei dipendenti e recuperare la colonna first_name delle righe nella tabella.

Esempio

(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)))

Dal codice sopra, possiamo vederlo

  • La query di "seleziona first_name da dipendente" viene passata come stringa di query.

  • Il: first_name è la sequenza, che viene restituita come risultato dell'operazione di recupero.

Se assumiamo che ci sia solo una riga nel nostro database che contiene un valore first_name di John, il seguente sarà l'output del programma precedente.

(John)

Inserimento di dati

È necessario quando si desidera creare i record in una tabella di database. Di seguito è riportata la sintassi con cui i dati possono essere inseriti utilizzando Clojure. Questo viene fatto usando il‘insert!’ funzione.

Sintassi

clojure.java.jdbc/insert!
   :table_name {:column_namen columnvalue}

Parameters- ': table_name' è il nome della tabella in cui deve essere effettuato l'inserimento. "{: column_namen columnvalue}" è una mappa di tutti i nomi e i valori delle colonne, che devono essere aggiunti come riga nella tabella.

Return Value - Questo restituirà zero se l'inserimento viene effettuato con successo.

L'esempio seguente mostra come inserire un record nella tabella dei dipendenti nel database testdb.

Esempio

(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 ora controlli il tuo database MySQL e la tabella dei dipendenti, vedrai che la riga sopra verrà inserita correttamente nella tabella.

Eliminazione dei dati

Le righe possono essere eliminate da una tabella utilizzando il ‘delete!’funzione. Di seguito è riportata la sintassi su come eseguire questa operazione.

Sintassi

clojure.java.jdbc/delete!
   :table_name [condition]

Parameters- ': table_name' è il nome della tabella in cui deve essere effettuato l'inserimento. "condition" è la condizione utilizzata per determinare quale riga deve essere eliminata dalla tabella.

Return Value - Questo restituirà il numero di righe eliminate.

L'esempio seguente mostra come eliminare un record dalla tabella dei dipendenti nel database testdb. L'esempio elimina una riga dalla tabella in base alla condizione che l'età sia uguale a 30.

Esempio

(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 hai un record con una riga con età uguale al valore di 30, quella riga verrà eliminata.

Aggiornamento dei dati

Le righe possono essere aggiornate da una tabella utilizzando il ‘update!’funzione. Di seguito è riportata la sintassi su come eseguire questa operazione.

Sintassi

clojure.java.jdbc/update!
   :table_name
{setcondition}
[condition]

Parameters- ': table_name' è il nome della tabella in cui deve essere effettuato l'inserimento. 'setcondition' è la colonna che deve essere aggiornata come indicato in termini di mappa. "condition" è la condizione utilizzata per determinare quale riga deve essere eliminata dalla tabella.

Return Value - Questo restituirà il numero di righe aggiornate.

L'esempio seguente mostra come eliminare un record dalla tabella dei dipendenti nel database testdb. L'esempio aggiorna una riga della tabella in base alla condizione che l'età sia uguale a 30 e aggiorna il valore del reddito a 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 avevi un record con una riga con età pari al valore di 30, quella riga verrà aggiornata in cui il valore del reddito sarà impostato a 40.

Transazioni

Le transazioni sono meccanismi che garantiscono la coerenza dei dati. Le transazioni hanno le seguenti quattro proprietà:

  • Atomicity - O una transazione viene completata o non accade nulla.

  • Consistency - Una transazione deve iniziare in uno stato coerente e lasciare il sistema in uno stato coerente.

  • Isolation - I risultati intermedi di una transazione non sono visibili al di fuori della transazione corrente.

  • Durability - Una volta che una transazione è stata confermata, gli effetti sono persistenti, anche dopo un errore di sistema.

Esempio

L'esempio seguente mostra come implementare le transazioni in Clojure. Qualsiasi operazione che deve essere eseguita in una transazione deve essere incorporata nel file‘with-dbtransaction’ clausola.

(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])))

Come già sappiamo, alla fine il codice Clojure viene eseguito sull'ambiente virtuale Java. Quindi ha senso solo che Clojure sia in grado di utilizzare tutte le funzionalità di Java. In questo capitolo, discutiamo la correlazione tra Clojure e Java.

Richiamo di metodi Java

I metodi Java possono essere chiamati utilizzando la notazione punto. Un esempio sono le stringhe. Poiché tutte le stringhe in Clojure sono comunque stringhe Java, è possibile chiamare i normali metodi Java sulle stringhe.

Un esempio di come questo è fatto è mostrato nel seguente programma.

Esempio

(ns Project
   (:gen-class))
(defn Example []
   (println (.toUpperCase "Hello World")))
(Example)

Il programma precedente produce il seguente output. Puoi vedere dal codice che se chiami solo la notazione del punto per qualsiasi metodo di stringa, funzionerà anche in Clojure.

Produzione

HELLO WORLD

Richiamo di metodi Java con parametri

È inoltre possibile chiamare metodi Java con parametri. Un esempio di come questo è fatto è mostrato nel seguente programma.

Esempio

(ns Project
   (:gen-class))
(defn Example []
   (println (.indexOf "Hello World","e")))
(Example)

Il programma precedente produce il seguente output. Puoi vedere dal codice sopra, che stiamo passando il parametro "e" al metodo indexOf. Il programma precedente produce il seguente output.

Produzione

1

Creazione di oggetti Java

Gli oggetti possono essere creati in Clojure utilizzando la parola chiave "new" simile a quanto fatto in Java.

Un esempio di come questo è fatto è mostrato nel seguente programma.

Esempio

(ns Project
   (:gen-class))
(defn Example []
   (def str1 (new String "Hello"))
   (println str1))
(Example)

Il programma precedente produce il seguente output. Puoi vedere dal codice sopra, che possiamo usare la parola chiave 'new' per creare un nuovo oggetto dalla classe String esistente da Java. Possiamo passare il valore durante la creazione dell'oggetto, proprio come facciamo in Java. Il programma precedente produce il seguente output.

Produzione

Hello

Di seguito è riportato un altro esempio che mostra come possiamo creare un oggetto della classe Integer e usarli nei normali comandi Clojure.

Esempio

(ns Project
   (:gen-class))
(defn Example []
   (def my-int(new Integer 1))
   (println (+ 2 my-int)))
(Example)

Il programma precedente produce il seguente output.

Produzione

3

Importa comando

Possiamo anche utilizzare il comando import per includere le librerie Java nello spazio dei nomi in modo che sia facile accedere alle classi e ai metodi.

Il seguente esempio mostra come possiamo usare il comando import. Nell'esempio stiamo usando il comando import per importare le classi dal filejava.util.stackbiblioteca. Possiamo quindi utilizzare il metodo push e pop della classe stack così come sono.

Esempio

(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)

Il programma precedente produce il seguente output.

Produzione

First Element

Codice in esecuzione utilizzando il comando Java

Il codice Clojure può essere eseguito utilizzando il comando Java. Di seguito è la sintassi di come questo può essere fatto.

java -jar clojure-1.2.0.jar -i main.clj

Devi menzionare il file jar Clojure, in modo che tutte le classi basate su Clojure vengano caricate nella JVM. Il file 'main.clj' è il file di codice Clojure che deve essere eseguito.

Funzioni integrate di Java

Clojure può utilizzare molte delle funzioni integrate di Java. Alcuni di loro sono -

Math PI function- Clojure può utilizzare il metodo Math al valore di PI. Di seguito è riportato un codice di esempio.

Esempio

(ns Project
   (:gen-class))
(defn Example []
   (println (. Math PI)))
(Example)

Il codice precedente produce il seguente output.

Produzione

3.141592653589793

System Properties- Clojure può anche interrogare le proprietà del sistema. Di seguito è riportato un codice di esempio.

Esempio

(ns Project
   (:gen-class))
(defn Example []
   (println (.. System getProperties (get "java.version"))))
(Example)

A seconda della versione di Java sul sistema, verrà visualizzato il valore corrispondente. Di seguito è riportato un esempio di output.

Produzione

1.8.0_45

Nella programmazione Clojure la maggior parte dei tipi di dati sono immutabili, quindi quando si tratta di programmazione simultanea, il codice che utilizza questi tipi di dati è abbastanza sicuro quando il codice viene eseguito su più processori. Ma molte volte è necessario condividere i dati e, quando si tratta di dati condivisi tra più processori, diventa necessario garantire che lo stato dei dati sia mantenuto in termini di integrità quando si lavora con più processori. Questo è noto comeconcurrent programming e Clojure fornisce supporto per tale programmazione.

Il sistema di memoria transazionale software (STM), esposto tramite dosync, ref, set, alter, ecc. Supporta la condivisione dello stato di cambiamento tra i thread in modo sincrono e coordinato. Il sistema dell'agente supporta la condivisione dello stato di cambiamento tra i thread in modo asincrono e indipendente. Il sistema degli atomi supporta la condivisione dello stato di cambiamento tra i thread in modo sincrono e indipendente. Mentre il sistema var dinamico, esposto tramite def, binding, ecc. Supporta l'isolamento del cambiamento di stato all'interno dei thread.

Anche altri linguaggi di programmazione seguono il modello per la programmazione concorrente.

  • Hanno un riferimento diretto ai dati che possono essere modificati.

  • Se è richiesto l'accesso condiviso, l'oggetto viene bloccato, il valore viene modificato e il processo continua per il successivo accesso a quel valore.

In Clojure non ci sono blocchi, ma riferimenti indiretti a strutture di dati persistenti immutabili.

Ci sono tre tipi di riferimenti in Clojure.

  • Vars - Le modifiche sono isolate nei thread.

  • Refs - Le modifiche vengono sincronizzate e coordinate tra i thread.

  • Agents - Coinvolge modifiche indipendenti asincrone tra i thread.

Le seguenti operazioni sono possibili in Clojure per quanto riguarda la programmazione concorrente.

Transazioni

La concorrenza in Clojure si basa sulle transazioni. I riferimenti possono essere modificati solo all'interno di una transazione. Le seguenti regole vengono applicate nelle transazioni.

  • Tutti i cambiamenti sono atomici e isolati.
  • Ogni modifica a un riferimento avviene in una transazione.
  • Nessuna transazione vede l'effetto prodotto da un'altra transazione.
  • Tutte le transazioni vengono inserite all'interno del blocco dosync.

Abbiamo già visto cosa fa il blocco dosync, guardiamolo di nuovo.

dosync

Esegue l'espressione (in un do implicito) in una transazione che comprende l'espressione e tutte le chiamate annidate. Avvia una transazione se nessuna è già in esecuzione su questo thread. Qualsiasi eccezione non rilevata interromperà la transazione e uscirà da dosync.

Di seguito è riportata la sintassi.

Sintassi

(dosync expression)

Parameters - "espressione" è l'insieme di espressioni che arriverà nel blocco dosync.

Return Value - Nessuno.

Diamo un'occhiata a un esempio in cui proviamo a cambiare il valore di una variabile di riferimento.

Esempio

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def names (ref []))
   (alter names conj "Mark"))
(Example)

Produzione

Il programma di cui sopra quando viene eseguito dà il seguente errore.

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

Dall'errore puoi vedere chiaramente che non puoi modificare il valore di un tipo di riferimento senza prima avviare una transazione.

Affinché il codice precedente funzioni, dobbiamo posizionare il comando alter in un blocco dosync come fatto nel programma seguente.

Esempio

(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)

Il programma precedente produce il seguente output.

Produzione

[John Mark]

Vediamo un altro esempio di dosync.

Esempio

(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)

Nell'esempio sopra, abbiamo due valori che vengono modificati in un blocco dosync. Se la transazione ha esito positivo, entrambi i valori cambieranno altrimenti l'intera transazione fallirà.

Il programma precedente produce il seguente output.

Produzione

10 20
-10 40

Clojure ha alcune biblioteche che hanno l'abilitazione per la creazione Desktop e Web-based applications. Parliamo di ognuno di loro.

Sr.No. Applicazioni e descrizione
1 Desktop - Altalena

See-saw è una libreria che può essere utilizzata per creare applicazioni desktop.

2 Desktop - Modifica del valore del testo

Il valore del contenuto nella finestra può essere modificato utilizzando il ‘config!’opzione. Nell'esempio seguente il file config! L'opzione viene utilizzata per modificare il contenuto della finestra con il nuovo valore "Good Bye".

3 Desktop - Visualizzazione di una finestra di dialogo modale

È possibile visualizzare una finestra di dialogo modale utilizzando il metodo di avviso della classe altalenante. Il metodo accetta il valore di testo, che deve essere mostrato nella finestra di dialogo modale.

4 Desktop - Visualizzazione dei pulsanti

I pulsanti possono essere visualizzati con l'aiuto della classe dei pulsanti.

5 Desktop - Visualizzazione di etichette

Le etichette possono essere visualizzate con l'aiuto della classe label.

6 Desktop - Visualizzazione dei campi di testo

I campi di testo possono essere visualizzati con l'aiuto della classe di testo.

Applicazioni Web - Introduzione

Per creare un'applicazione web in Clojure è necessario utilizzare la libreria dell'applicazione Ring, disponibile al seguente link https://github.com/ring-clojure/ring

Devi assicurarti di scaricare i jar necessari dal sito e assicurarti di aggiungerli come dipendenza per l'applicazione Clojure.

Il Ring framework fornisce le seguenti funzionalità:

  • Imposta le cose in modo tale che una richiesta http arrivi nella tua applicazione web come una normale Clojure HashMap, e allo stesso modo fa in modo che tu possa restituire una risposta come HashMap.

  • Fornisce una specifica che descrive esattamente come dovrebbero apparire quelle mappe di richiesta e risposta.

  • Porta con sé un server web (Jetty) e collega ad esso la tua applicazione web.

Il framework Ring può avviare automaticamente un server web e garantisce che l'applicazione Clojure funzioni su questo server. Quindi si può anche utilizzare il framework Compojure. Ciò consente di creare percorsi che è ora il modo in cui vengono sviluppate le più moderne applicazioni web.

Creating your first Clojure application - Il seguente esempio mostra come creare la tua prima applicazione web in 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))

Diamo un'occhiata ai seguenti aspetti del programma:

  • Il ‘defroutes’ viene utilizzato per creare percorsi in modo che la richiesta fatta all'applicazione Web a percorsi diversi possa essere indirizzata a diverse funzioni nell'applicazione Clojure.

  • Nell'esempio precedente, la "/" è nota come route predefinita, quindi quando navighi alla base della tua applicazione web, la stringa "Hello World" verrà inviata al browser web.

  • Se l'utente colpisce un URL che non può essere elaborato dall'applicazione Clojure, visualizzerà la stringa "Not Found".

Quando esegui l'applicazione Clojure, per impostazione predefinita la tua applicazione verrà caricata come localhost: 3000, quindi se navighi in questa posizione, riceverai il seguente output.

Applicazioni Web: aggiunta di più percorsi alla tua applicazione Web

Puoi anche aggiungere più percorsi alla tua applicazione web. Il seguente esempio mostra come ottenere questo risultato.

(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))

Puoi vedere che aggiungere una route nell'applicazione è facile come aggiungere un'altra funzione GET con l'URL route. (GET "/ Tutorial" [] "Questo è un tutorial su Clojure")

Se navighi nella posizione http://localhost:3000/Tutorial, riceverai il seguente output.

In questo capitolo, discuteremo le opzioni di test automatizzato fornite da Clojure.

Test per applicazioni client

Per poter usare il testing per il framework Clojure, devi usare le dipendenze che si trovano in https://github.com/slagyr/speclj#manual-installation

Questo URL fornisce il specljframework, che viene utilizzato come framework di test basato sui dati di test o basato sul comportamento per Clojure. Devi assicurarti di usare il framework Clojure 1.7.0 quando usi una qualsiasi delle librerie 'speclj'. Per impostazione predefinita, i file di test saranno diversi dai file di codice Clojure e devono essere inseriti in una directory "spec".

Di seguito è riportato un codice di esempio per un file di prova.

(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)

Le seguenti cose devono essere annotate sul codice sopra:

  • Per prima cosa dobbiamo assicurarci di utilizzare l'istruzione "require" per includere tutte le librerie principali nel framework "speclj".

  • La prossima è la funzione "Descrivi". Viene utilizzato per fornire una descrizione per lo scenario di test da creare.

  • La funzione successiva è la funzione "it", che è il vero caso di test. Nel primo caso di test, la stringa "è vero" è il nome dato allo scenario di test.

  • Dovrebbe e non dovrebbe-non sono conosciuti come assertions. Tutte le affermazioni iniziano con dovrebbe. Dovrebbe e non dovrebbe sono solo due delle tante affermazioni disponibili. Entrambi prendono espressioni che cercheranno rispettivamente di veridicità e falsità.

Se esegui il test case, otterrai il seguente output. L'output mostra il tempo impiegato in millisecondi per l'esecuzione del test case.

←[32m.←[0m←[32m.←[0m
Finished in 0.00014 seconds

Test per applicazioni basate sul Web

Seleniumè uno dei framework chiave utilizzati per testare le moderne applicazioni basate sul web. Sono disponibili anche librerie Clojure che possono essere utilizzate per testare applicazioni basate sul web.

Diamo un'occhiata a come possiamo utilizzare le librerie Selenium per testare le applicazioni basate sul web Clojure.

Step 1- Il primo passo è assicurarsi di utilizzare il framework Ring e Compojure per creare un'applicazione basata sul Web, che deve essere testata. Usiamo uno degli esempi dei nostri capitoli precedenti. Il codice seguente è una semplice applicazione web, che visualizza "Hello World" nel browser.

(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 - Quindi assicurati di scaricare il file jar di selenio https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server/2.47.0 e includilo nel tuo classpath.

Step 3 - Assicurati inoltre di scaricare il driver web "clj", che verrà utilizzato per eseguire il test web dal seguente percorso.

https://clojars.org/clj-webdriver/versions/0.7.1

Step 4 - Nella directory del progetto, crea un'altra directory chiamata features e crea un file chiamato "config.clj".

Step 5 - Successivamente aggiungi il seguente codice al file "config.clj" creato nel passaggio precedente.

ns clj-webdriver-tutorial.features.config)
(def test-port 3000)
(def test-host "localhost")
(def test-base-url (str "http://" test-host ":" test-port "/"))

Il codice sopra in pratica dice al framework di test web di testare l'applicazione, che viene caricata all'URL http://localhost:3000

Step 6 - Infine, scriviamo il nostro codice per effettuare il nostro test.

(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)))

Il codice sopra eseguirà le seguenti azioni:

  • Avvia il server per l'applicazione.
  • Apri il percorso principale nel browser.
  • Controlla se il messaggio "Hello World" è presente nella pagina.
  • Chiudi il browser.
  • Spegni il server.

Una cosa che rende la libreria Clojure così potente è il numero di librerie disponibili per il framework Clojure. Abbiamo già visto così tante librerie utilizzate nei nostri esempi precedenti per test web, sviluppo web, sviluppo di applicazioni basate su swing, la libreria jdbc per la connessione ai database MySQL. Di seguito sono riportati solo un paio di esempi di poche altre librerie.

data.xml

Questa libreria consente a Clojure di lavorare con i dati XML. La versione della libreria da utilizzare è org.clojure / data.xml "0.0.8". Data.xml supporta l'analisi e l'emissione di XML. Le funzioni di analisi leggeranno XML da un Reader o InputStream.

Esempio

Di seguito è riportato un esempio dell'elaborazione dei dati da una stringa a 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

Questa libreria consente a Clojure di lavorare con i dati JSON. La versione della libreria da utilizzare è org.clojure / data.json "0.2.6".

Esempio

Di seguito è riportato un esempio sull'uso di questa libreria.

(ns clojure.examples.example
   (:require [clojure.data.json :as json])
   (:gen-class))
(defn Example []
   (println (json/write-str {:a 1 :b 2})))
(Example)

Produzione

Il programma precedente produce il seguente output.

{\"a\":1,\"b\":2}

data.csv

Questa libreria consente a Clojure di lavorare con ‘csv’dati. La versione della libreria da utilizzare è org.clojure / data.csv "0.1.3".

Esempio

Di seguito è riportato un esempio sull'uso di questa libreria.

(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)

Nel codice precedente, la funzione "csv" leggerà prima un file chiamato in-file.csve inserisci tutti i dati nella variabile in-file. Successivamente, stiamo usando la funzione write-csv per scrivere tutti i dati in un file chiamatoout-file.csv.