Clojure - Szybki przewodnik
Clojure to dynamiczny, funkcjonalny język programowania wysokiego poziomu. Clojure jest zaprojektowany w oparciu o język programowania LISP i posiada kompilatory, dzięki czemu działa zarówno w środowisku uruchomieniowym Java, jak i .Net.
Zanim porozmawiamy o Clojure, zróbmy krótki opis języka programowania LISP. LISP-y mają mały rdzeń językowy, prawie bez składni i potężną funkcję makr. Dzięki tym funkcjom możesz zginać LISP zgodnie z projektem, a nie odwrotnie. LISP istnieje od dawna, sięgając 1958 roku.
Zwykły LISP czyta wyrażenie, ocenia je, a następnie wypisuje wynik. Na przykład, jeśli chcesz obliczyć wartość prostego wyrażenia matematycznego 4 + 6, wpisz.
USER(1) (+ 4 6)
Clojure ma następujące kluczowe cele wysokiego poziomu jako język programowania.
Opiera się na języku programowania LISP, dzięki czemu jego instrukcje w kodzie są mniejsze niż w tradycyjnych językach programowania.
Jest to funkcjonalny język programowania.
Koncentruje się na niezmienności, która jest zasadniczo koncepcją, że nie należy wprowadzać żadnych zmian w obiektach, które są tworzone w miejscu.
Może zarządzać stanem aplikacji dla programisty.
Obsługuje współbieżność.
Obejmuje istniejące języki programowania. Na przykład Clojure może korzystać z całego ekosystemu Java do zarządzania uruchomieniem kodu za pośrednictwem JVM.
Oficjalna strona internetowa Clojure to https://clojure.org/
Istnieje wiele sposobów pracy z Clojure jako językiem programowania. Przyjrzymy się dwóm sposobom pracy z programowaniem Clojure.
Leiningen - Leiningen to podstawowe narzędzie do tworzenia, budowania i automatyzacji projektów Clojure.
Eclipse Plugin - Istnieje wtyczka o nazwie CounterClockwise, która jest dostępna dla Eclipse do prowadzenia rozwoju Clojure w środowisku Eclipse IDE.
Instalacja Leiningen
Przed przystąpieniem do instalacji upewnij się, że spełnione są następujące wymagania systemowe.
wymagania systemowe
JDK | JDK 1.7 lub nowszy |
---|---|
Pamięć | 2 GB RAM (zalecane) |
Step 1- Pobierz instalację binarną. Przejdź do linkuhttp://leiningen-wininstalleraby pobrać Instalatora Windows. Kliknij opcję, aby rozpocząć pobieranie instalatora Groovy.
Step 2 - Uruchom Instalatora i kliknij przycisk Dalej.
Step 3 - Określ lokalizację instalacji i kliknij przycisk Dalej.
Step 4- Instalator wykryje lokalizację istniejącej instalacji Java. Kliknij przycisk Dalej, aby kontynuować.
Step 5 - Kliknij przycisk Instaluj, aby rozpocząć instalację.
Po zakończeniu instalacji będzie można otworzyć Clojure REPL, czyli środowisko, którego można używać do tworzenia i testowania programów Clojure.
Instalacja Eclipse
Przed przystąpieniem do instalacji upewnij się, że spełnione są następujące wymagania systemowe.
wymagania systemowe
JDK | JDK 1.7 lub nowszy |
---|---|
Zaćmienie | Eclipse 4.5 (Mars) |
Step 1- Otwórz Eclipse i kliknij element Menu. Kliknij Pomoc → Eclipse Marketplace.
Step 2- Wpisz słowo kluczowe Clojure w wyświetlonym oknie dialogowym i naciśnij przycisk „Idź”. Pojawi się opcja przeciwnie do ruchu wskazówek zegara, kliknij przycisk Instaluj, aby rozpocząć instalację tej wtyczki.
Step 3 - W następnym oknie dialogowym kliknij przycisk Potwierdź, aby rozpocząć instalację.
Step 4- W następnym oknie dialogowym zostaniesz poproszony o zaakceptowanie umowy licencyjnej. Zaakceptuj umowę licencyjną i kliknij przycisk Zakończ, aby kontynuować instalację.
Instalacja rozpocznie się, a po jej zakończeniu wyświetli się monit o ponowne uruchomienie Eclipse.
Po ponownym uruchomieniu Eclipse zobaczysz opcję w Eclipse, aby utworzyć nowy projekt Clojure.
Aby zrozumieć podstawową składnię Clojure, przyjrzyjmy się najpierw prostemu programowi Hello World.
Hello World jako kompletny program
Napisz „Hello world” w kompletnym programie Clojure. Oto przykład.
Przykład
(ns clojure.examples.hello
(:gen-class))
(defn hello-world []
(println "Hello World"))
(hello-world)
Na temat powyższego programu należy zwrócić uwagę na następujące kwestie.
Program zostanie zapisany w pliku o nazwie main.clj. Rozszerzenie „clj” to nazwa rozszerzenia pliku kodu clojure. W powyższym przykładzie nazwa pliku to main.clj.
Słowo kluczowe „defn” służy do definiowania funkcji. Szczegóły funkcji zobaczymy w innym rozdziale. Ale na razie wiedz, że tworzymy funkcję o nazwie helloworld, która będzie miała nasz główny kod Clojure.
W naszym kodzie Clojure używamy instrukcji „println” do wypisywania „Hello World” na wyjściu konsoli.
Następnie wywołujemy funkcję hello-world, która z kolei uruchamia instrukcję „println”.
Powyższy program generuje następujące dane wyjściowe.
Wynik
Hello World
Ogólna forma oświadczenia
Ogólną postać każdej instrukcji należy ocenić w nawiasach klamrowych, jak pokazano w poniższym przykładzie.
(+ 1 2)
W powyższym przykładzie całe wyrażenie jest zawarte w nawiasach. Wynik powyższej instrukcji to 3. Operator + działa jak funkcja w Clojure, która służy do dodawania liczb. Wartości 1 i 2 są znane jako parameters to the function.
Rozważmy inny przykład. W tym przykładzie „str” jest operatorem używanym do konkatenacji dwóch ciągów. Jako parametry używane są ciągi „Hello” i „World”.
(str "Hello" "World")
Przykład
Jeśli połączymy powyższe dwie instrukcje i napiszemy program, będzie on wyglądał następująco.
(ns clojure.examples.hello
(:gen-class))
(defn Example []
(println (str "Hello World"))
(println (+ 1 2)))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe.
Hello World
3
Przestrzenie nazw
Przestrzeń nazw służy do definiowania logicznej granicy między modułami zdefiniowanymi w Clojure.
Bieżąca przestrzeń nazw
Definiuje bieżącą przestrzeń nazw, w której znajduje się bieżący kod Clojure.
Składnia
*ns*
Przykład
W oknie polecenia REPL uruchom następujące polecenie.
*ns*
Wynik
Kiedy uruchomimy powyższe polecenie, dane wyjściowe zostaną odroczone w zależności od bieżącej przestrzeni nazw. Poniżej znajduje się przykład wyniku. Przestrzeń nazw kodu Clojure to -
clojure.examples.hello
(ns clojure.examples.hello
(:gen-class))
(defn Example []
(println (str "Hello World"))
(println (+ 1 2)))
(Example)
Wymagaj oświadczenia w Clojure
Kod Clojure jest spakowany w bibliotekach. Każda biblioteka Clojure należy do przestrzeni nazw, która jest analogiczna do pakietu Java. Bibliotekę Clojure można załadować za pomocą instrukcji „Require”.
Składnia
(require quoted-namespace-symbol)
Przykład
Poniżej znajduje się przykład użycia tego oświadczenia.
(ns clojure.examples.hello
(:gen-class))
(require ‘clojure.java.io’)
(defn Example []
(.exists (file "Example.txt")))
(Example)
W powyższym kodzie używamy słowa kluczowego „require” do importowania przestrzeni nazw clojure.java.io, która ma wszystkie funkcje wymagane do obsługi wejścia / wyjścia. Ponieważ nie mamy wymaganej biblioteki, możemy użyć funkcji „plik” w powyższym kodzie.
Komentarze w Clojure
Komentarze służą do dokumentowania Twojego kodu. Komentarze jednowierszowe są identyfikowane za pomocą ;; w dowolnym miejscu w linii. Oto przykład.
Przykład
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println "Hello World"))
(Example)
Ograniczniki
W Clojure instrukcje można dzielić lub ograniczać za pomocą nawiasów kwadratowych lub zakrzywionych.
Przykład
Oto dwa przykłady.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println (+ 1 2 3)))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe.
6
Przykład
Oto kolejny przykład.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println [+ 1 2 3]))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe.
[#object[clojure.core$_PLUS_ 0x10f163b "clojure.core$_PLUS_@10f163b"] 1 2 3]
Białe spacje
W Clojure można używać białych znaków do dzielenia różnych składników instrukcji w celu uzyskania większej przejrzystości. Można to zrobić za pomocą operatora przecinka (,).
Na przykład następujące dwie instrukcje są równoważne, a wynikiem obu instrukcji będzie 15.
(+ 1 2 3 4 5)
(+ 1, 2, 3, 4, 5)
Chociaż Clojure ignoruje przecinki, czasami używa ich, aby ułatwić programiście czytanie.
Na przykład, jeśli masz mapę mieszającą taką jak poniżej (def a-map {: a 1: b 2: c 3}) i poprosisz o jej wartość w oknie REPL, Clojure wydrukuje wynik jako {: a 1, : b 2,: c 3}.
Wyniki są łatwiejsze do odczytania, zwłaszcza jeśli patrzysz na dużą ilość danych.
Symbolika
W Clojure symbole są równoważne z identyfikatorami w innych językach programowania. Ale w przeciwieństwie do innych języków programowania, kompilator widzi symbole jako rzeczywiste wartości łańcuchowe. Ponieważ symbol jest wartością, symbol może być przechowywany w kolekcji, przekazywany jako argument do funkcji itp., Tak jak każdy inny obiekt.
Symbol może zawierać tylko znaki alfanumeryczne i „* +! /. : - _? ' ale nie może zaczynać się od cyfry ani dwukropka.
Poniżej znajdują się ważne przykłady symboli.
tutorial-point!
TUTORIAL
+tutorial+
Struktura projektu Clojure
Na koniec porozmawiajmy o typowej strukturze projektu dla projektu Clojure. Ponieważ kod Clojure działa na wirtualnej maszynie Java, większość struktury projektu w Clojure jest podobna do tej, którą można znaleźć w projekcie Java. Poniżej znajduje się migawka przykładowej struktury projektu w Eclipse dla projektu Clojure.
Należy zwrócić uwagę na następujące kluczowe rzeczy dotyczące powyższej struktury programu.
demo_1 - jest to pakiet, w którym umieszczony jest plik kodu Clojure.
core.clj - jest to główny plik kodu Clojure, który będzie zawierał kod aplikacji Clojure.
Folder Leiningen zawiera pliki, takie jak clojure-1.6.0.jar, które są wymagane do uruchomienia dowolnej aplikacji opartej na Clojure.
Plik pom.properties będzie zawierał informacje, takie jak groupId, artifactId i wersja projektu Clojure.
Plik project.clj zawiera informacje o samej aplikacji Clojure. Poniżej znajduje się przykład zawartości pliku projektu.
(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) to narzędzie do eksperymentowania z kodem Clojure. Pozwala na interakcję z uruchomionym programem i szybkie sprawdzenie, czy wszystko działa tak, jak powinno. Czyni to, wyświetlając monit, w którym można wprowadzić kod. Następnie odczytuje wprowadzone dane, ocenia je, drukuje wynik i wykonuje pętlę, ponownie przedstawiając monit.
Ten proces umożliwia szybki cykl informacji zwrotnej, który nie jest możliwy w większości innych języków.
Rozpoczynanie sesji REPL
Sesję REPL można uruchomić w Leiningen, wpisując następujące polecenie w wierszu poleceń.
lein repl
Spowoduje to uruchomienie następującego okna REPL.
Następnie zacznij oceniać polecenia Clojure w oknie REPL zgodnie z wymaganiami.
Aby rozpocząć sesję REPL w Eclipse, kliknij opcję Menu, przejdź do Uruchom jako → Aplikacja Clojure.
Spowoduje to rozpoczęcie nowej sesji REPL w osobnym oknie wraz z danymi wyjściowymi konsoli.
Pod względem koncepcyjnym REPL jest podobny do Secure Shell (SSH). W ten sam sposób, w jaki możesz używać SSH do interakcji ze zdalnym serwerem, Clojure REPL umożliwia interakcję z działającym procesem Clojure. Ta funkcja może być bardzo potężna, ponieważ możesz nawet dołączyć REPL do aplikacji produkcyjnej na żywo i modyfikować program w trakcie jego działania.
Zmienne specjalne w REPL
REPL zawiera kilka użytecznych zmiennych, z których najczęściej używaną jest zmienna specjalna * 1, * 2 i * 3. Są one używane do oceny wyników trzech ostatnich wyrażeń.
Poniższy przykład pokazuje, jak te zmienne mogą być używane.
user => "Hello"
Hello
user => "World"
World
user => (str *2 *1)
HelloWorld
W powyższym przykładzie pierwsze dwa ciągi są wysyłane do okna wyjściowego REPL odpowiednio jako „Hello” i „World”. Następnie zmienne * 2 i * 1 są używane do przywołania ostatnich 2 ocenianych wyrażeń.
Clojure oferuje szeroką gamę plików built-in data types.
Wbudowane typy danych
Poniżej znajduje się lista typów danych, które są zdefiniowane w Clojure.
Integers - Poniżej przedstawiono reprezentację liczb całkowitych dostępnych w Clojure.
Decimal Integers (Short, Long and Int)- Są używane do przedstawiania liczb całkowitych. Na przykład 1234.
Octal Numbers- Są używane do przedstawiania liczb w reprezentacji ósemkowej. Na przykład 012.
Hexadecimal Numbers- Są używane do reprezentowania liczb w reprezentacji. Na przykład 0xff.
Radix Numbers- Są używane do reprezentowania liczb w reprezentacji radix. Na przykład 2r1111, gdzie podstawa jest liczbą całkowitą od 2 do 36 włącznie.
Floating point
Wartość domyślna jest używana do reprezentowania 32-bitowych liczb zmiennoprzecinkowych. Na przykład 12.34.
Drugą reprezentacją jest notacja naukowa. Na przykład 1,35e-12.
char- definiuje literał pojedynczego znaku. Znaki są definiowane za pomocą symbolu luzu. Na przykład / e.
Boolean - reprezentuje wartość logiczną, która może być prawdą lub fałszem.
String- Są to literały tekstowe, które są przedstawiane w postaci ciągu znaków. Na przykład „Hello World”.
Nil - Służy do reprezentowania wartości NULL w Clojure.
Atom- Atomy umożliwiają zarządzanie współdzielonym, synchronicznym, niezależnym stanem. Są typem referencyjnym, takim jak refs i vars.
Wartości powiązane
Ponieważ wszystkie typy danych w Clojure są dziedziczone z Javy, ograniczone wartości są takie same jak w języku programowania Java. W poniższej tabeli przedstawiono maksymalne dozwolone wartości literałów liczbowych i dziesiętnych.
dosłowne | Zakresy |
---|---|
Krótki | -32 768 do 32767 |
int | -2 147 483 648 do 2 147 483 647 |
długo | -9.223.372.036.854.775.808 do +9.223.372.036.854.775.807 |
pływak | 1.40129846432481707e-45 do 3.40282346638528860e + 38 |
podwójnie | 4.94065645841246544e-324d do 1.79769313486231570e + 308d |
Typy liczbowe klas
Oprócz typów pierwotnych dozwolone są następujące typy obiektów (czasami nazywane typami opakowań).
Nazwa |
---|
java.lang.Byte |
java.lang.Short |
java.lang.Integer |
java.lang.Long |
java.lang.Float |
java.lang.Double |
Przykład
Poniższy program przedstawia skonsolidowany kod clojure, aby zademonstrować typy danych w 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)
Wynik
Powyższy program generuje następujące dane wyjściowe.
1
1.25
Hello
W Clojure, variables są zdefiniowane przez ‘def’słowo kluczowe. Trochę inaczej jest, gdy pojęcie zmiennych ma więcej wspólnego z wiązaniem. W Clojure wartość jest powiązana ze zmienną. Jedną z kluczowych rzeczy, na które należy zwrócić uwagę w Clojure, jest to, że zmienne są niezmienne, co oznacza, że aby wartość zmiennej uległa zmianie, musi zostać zniszczona i ponownie utworzona.
Poniżej przedstawiono podstawowe typy zmiennych w Clojure.
short- Służy do reprezentowania krótkiej liczby. Na przykład 10.
int- Służy do reprezentowania liczb całkowitych. Na przykład 1234.
long- Służy do reprezentowania długiej liczby. Na przykład 10000090.
float- Służy do reprezentowania 32-bitowych liczb zmiennoprzecinkowych. Na przykład 12.34.
char- definiuje literał pojedynczego znaku. Na przykład „/ a”.
Boolean - reprezentuje wartość logiczną, która może być prawdą lub fałszem.
String- Są to literały tekstowe, które są przedstawiane w postaci ciągu znaków. Na przykład „Hello World”.
Deklaracje zmiennych
Poniżej znajduje się ogólna składnia definiowania zmiennej.
Składnia
(def var-name var-value)
Gdzie „nazwa-zmiennej” to nazwa zmiennej, a „wartość-zmienna” to wartość powiązana ze zmienną.
Przykład
Poniżej znajduje się przykład deklaracji zmiennej.
(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)
Nazewnictwo zmiennych
Nazwa zmiennej może składać się z liter, cyfr i znaku podkreślenia. Musi zaczynać się od litery lub podkreślenia. Wielkie i małe litery są różne, ponieważ Clojure, podobnie jak Java, jest językiem programowania uwzględniającym wielkość liter.
Przykład
Oto kilka przykładów nazewnictwa zmiennych w 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 - W powyższych stwierdzeniach, ze względu na rozróżnianie wielkości liter, status i STATUS to dwie różne definicje zmiennych w Clojure.
Powyższy przykład pokazuje, jak zdefiniować zmienną ze znakiem podkreślenia.
Drukowanie zmiennych
Ponieważ Clojure korzysta ze środowiska JVM, możesz również użyć funkcji „println”. Poniższy przykład pokazuje, jak można to osiągnąć.
Przykład
(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)
Wynik
Powyższy program generuje następujące dane wyjściowe.
1
1.25
Hello
Na operator to symbol, który mówi kompilatorowi, aby wykonał określone operacje matematyczne lub logiczne.
Clojure ma następujące typy operatorów -
- Operatory arytmetyczne
- Operatorzy relacyjni
- Operatory logiczne
- Operatory bitowe
Note - W Clojure operatory i operandy działają w następujący sposób.
Składnia
(operator operand1 operand2 operandn)
Na przykład,
Przykład
(+ 1 2)
Powyższy przykład wykonuje operację arytmetyczną na liczbach 1 i 2.
Operatory arytmetyczne
Język Clojure obsługuje zwykłe operatory arytmetyczne jak każdy inny język. Poniżej znajdują się operatory arytmetyczne dostępne w Clojure.
Pokaż przykłady
Operator | Opis | Przykład |
---|---|---|
+ | Dodanie dwóch operandów | (+ 1 2) da 3 |
- | Odejmuje drugi operand od pierwszego | (- 2 1) daje 1 |
* | Mnożenie obu operandów | (* 2 2) da 4 |
/ | Podział licznika przez mianownik | (float (/ 3 2)) daje 1,5 |
inc | Operatory przyrostowe używane do zwiększania wartości operandu o 1 | dod. 5 da 6 |
dec | Operatory przyrostowe używane do zmniejszania wartości operandu o 1 | dec 5 da 4 |
max | Zwraca największy ze swoich argumentów | max 1 2 3 zwróci 3 |
min | Zwraca najmniejszy z argumentów | min 1 2 3 zwróci 1 |
rem | Pozostała część podzielenia pierwszej liczby przez drugą | rem 3 2 da 1 |
Operatorzy relacyjni
Operatory relacyjne pozwalają na porównywanie obiektów. Poniżej znajdują się operatory relacyjne dostępne w Clojure.
Pokaż przykłady
Operator | Opis | Przykład |
---|---|---|
= | Testuje równość między dwoma obiektami | (= 2 2) da prawdę |
nie = | Testuje różnicę między dwoma obiektami | (nie = 3 2) da prawdę |
< | Sprawdza, czy lewy obiekt jest mniejszy niż prawy operand | (<2 3) da prawdę |
<= | Sprawdza, czy lewy obiekt jest mniejszy lub równy prawemu operandowi | (<= 2 3) da prawdę |
> | Sprawdza, czy lewy obiekt jest większy niż prawy operand | (> 3 2) da prawdę |
> = | Sprawdza, czy lewy obiekt jest większy lub równy prawemu operandowi | (> = 3 2) da prawdę |
Operatory logiczne
Operatory logiczne służą do oceny wyrażeń boolowskich. Poniżej znajdują się operatory logiczne dostępne w Groovy.
Pokaż przykłady
Operator | Opis | Przykład |
---|---|---|
and | To jest operator logiczny „i” | (lub prawda prawda) da prawdę |
or | To jest operator logiczny „lub” | (i prawda fałsz) da fałsz |
not | To jest logiczny operator „nie” | (nie fałsz) da prawdę |
Poniższy fragment kodu pokazuje, jak można używać różnych operatorów.
Operatory bitowe
Clojure udostępnia cztery operatory bitowe. Poniżej znajdują się operatory bitowe dostępne w Clojure.
Pokaż przykłady
Sr.No. | Operator i opis |
---|---|
1 | bit-and To jest operator bitowy „i” |
2 | bit-or To jest operator bitowy „lub” |
3 | bit-xor To jest bitowy operator „xor” lub „Exclusive” lub „ |
4 | bit-not To jest bitowy operator negacji |
Poniżej znajduje się tabela prawdy przedstawiająca te operatory.
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 |
Pierwszeństwo operatora
Tak jak ogólnie w przypadku LISP-ów, nie ma potrzeby martwić się o pierwszeństwo operatorów. Jest to jedna z zalet wyrażeń S i notacji przedrostków. Wszystkie funkcje są obliczane od lewej do prawej i od wewnątrz. Operatory w Clojure to tylko funkcje, a wszystko jest w nawiasach.
Do tej pory widzieliśmy instrukcje, które są wykonywane jedna po drugiej w sposób sekwencyjny. Ponadto Clojure zawiera instrukcje, które zmieniają przepływ sterowania w logice programu. Następnie są one klasyfikowane w strumieniu oświadczeń kontrolnych, które zobaczymy szczegółowo.
Sr.No. | Pętle i opis |
---|---|
1 | While Statement Plik 'while' wykonywana jest najpierw przez ocenę wyrażenia warunkowego (wartość logiczna), a jeśli wynik jest prawdziwy, wykonywane są instrukcje w pętli while. |
2 | Oświadczenie Doseq Plik ‘doseq’instrukcja jest podobna do instrukcji „for each”, którą można znaleźć w wielu innych językach programowania. Wyrażenie dawkiq jest zasadniczo używane do iteracji po sekwencji. |
3 | Oświadczenie Dotimes Plik ‘dotimes’ instrukcja służy do wykonywania instrukcji „x” wiele razy. |
4 | Instrukcja pętli Forma specjalna pętli nie jest podobna do ‘for’pętla. Użycie pętli jest takie samo jak w przypadku wiązania let. Jednak pętla ustawia punkt rekursji |
Decision-making structures wymagać, aby programista określił jeden lub więcej warunków do oceny lub przetestowania przez program, wraz z instrukcją lub instrukcjami do wykonania, jeśli warunek zostanie określony jako prawdziwy, i opcjonalnie inne instrukcje do wykonania, jeśli warunek zostanie określony jako być fałszywe.
Sr.No. | Metody i opis |
---|---|
1 | Jeśli instrukcja W Clojure warunek jest wyrażeniem, które ocenia go jako prawdę lub fałsz. 'If' warunek jest prawdziwy, wtedy zostanie wykonana instrukcja nr 1, w przeciwnym razie instrukcja nr 2 zostanie wykonana. |
2 | Jeśli / do Expression Plik ‘if-do’ wyrażenie w Clojure służy do umożliwienia wykonywania wielu wyrażeń dla każdej gałęzi instrukcji „if”. |
3 | Instrukcja zagnieżdżona If Wielokrotność 'if' instrukcje osadzone w sobie. |
4 | Instrukcja Case Clojure oferuje ‘case’ instrukcja, która jest podobna do ‘switch’ instrukcja dostępna w języku programowania Java. |
5 | Instrukcja Cond Clojure oferuje inne oświadczenie oceniające o nazwie ‘cond’komunikat. Ta instrukcja przyjmuje zestaw par test / wyrażenie. |
Clojure jest znany jako funkcjonalny język programowania, dlatego można się spodziewać dużego nacisku na sposób działania funkcji w Clojure. W tym rozdziale opisano, co można zrobić za pomocą funkcji Clojure.
Sr.No. | Funkcje i opis |
---|---|
1 | Definiowanie funkcji Funkcja jest definiowana przy użyciu ‘defn’ makro. |
2 | Funkcje anonimowe Funkcja anonimowa to funkcja, z którą nie jest skojarzona żadna nazwa. |
3 | Funkcje z wieloma argumentami Funkcje Clojure można zdefiniować z zerem lub większą liczbą parametrów. Nazywane są wartości, które przekazujesz do funkcjiarguments, a argumenty mogą być dowolnego typu. |
4 | Funkcje wariadyczne Clojure oferuje instrukcję „case”, która jest podobna do instrukcji „switch” dostępnej w języku programowania Java. |
5 | Funkcje wyższego rzędu Funkcje wyższego rzędu (HOF) to funkcje, które przyjmują inne funkcje jako argumenty. HOF są ważną techniką programowania funkcjonalnego i są dość powszechnie używane w Clojure. |
Numbers typ danych w Clojure pochodzi z klas Java.
Clojure obsługuje liczby całkowite i zmiennoprzecinkowe.
Liczba całkowita to wartość, która nie zawiera ułamka.
Liczba zmiennoprzecinkowa to wartość dziesiętna zawierająca ułamek dziesiętny.
Poniżej znajduje się przykład liczb w Clojure.
(def x 5)
(def y 5.25)
Gdzie „x” jest typu Integer a „y” to float.
W Javie następujące klasy są dołączone do liczb zdefiniowanych w Clojure.
Aby rzeczywiście zobaczyć, że liczby w Clojure pochodzą z klas Java, użyj następującego programu, aby zobaczyć typ liczb przypisanych podczas używania polecenia „def”.
Przykład
(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)
Plik ‘type’ polecenie służy do wyprowadzania klasy skojarzonej z wartością przypisaną do zmiennej.
Wynik
Powyższy kod wygeneruje następujące dane wyjściowe.
Java.lang.long
Java.lang.double
Testy liczbowe
Następujące funkcje testowe są dostępne dla liczb.
Sr.No. | Liczby i opis |
---|---|
1 | zero? Zwraca prawdę, jeśli liczba wynosi zero, w przeciwnym razie fałsz. |
2 | pos? Zwraca prawdę, jeśli liczba jest większa od zera, w przeciwnym razie fałsz. |
3 | neg? Zwraca prawdę, jeśli liczba jest mniejsza od zera, w przeciwnym razie fałsz. |
4 | parzysty? Zwraca wartość true, jeśli liczba jest parzysta, i zgłasza wyjątek, jeśli liczba nie jest liczbą całkowitą. |
5 | dziwny? Zwraca wartość true, jeśli liczba jest nieparzysta, i zgłasza wyjątek, jeśli liczba nie jest liczbą całkowitą. |
6 | numer? Zwraca wartość true, jeśli liczba jest naprawdę liczbą. |
7 | liczba całkowita? Zwraca wartość true, jeśli liczba jest liczbą całkowitą. |
8 | pływak? Zwraca wartość true, jeśli liczba jest liczbą zmiennoprzecinkową. |
Widzieliśmy stwierdzenie recur we wcześniejszym temacie i podczas gdy pętla „for” przypomina trochę pętlę, recur to prawdziwa pętla w Clojure.
Jeśli masz doświadczenie w programowaniu, być może słyszałeś o rekurencji ogonowej, która jest główną cechą języków funkcjonalnych. Ta specjalna forma cykliczna implementuje rekurencję ogonową. Jak wskazuje słowo „rekurencja ogona”, recur musi zostać wywołany w pozycji ogona. Innymi słowy, wartość recur musi być ostatnią oceną.
Najprostszy przykład instrukcji recur jest używany w pętli „for”. W poniższym przykładzie instrukcja recur jest używana do zmiany wartości zmiennej „i” i przekazania wartości zmiennej z powrotem do wyrażenia pętli.
Przykład
(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)
Wynik
Powyższy program generuje następujące dane wyjściowe.
0
1
2
3
4
Clojure zapewnia szereg pomocniczych metod podczas pracy z we / wy. Oferuje łatwiejsze klasy, aby zapewnić następujące funkcje dla plików.
- Czytanie plików
- Pisanie do plików
- Sprawdzanie, czy plik jest plikiem lub katalogiem
Przyjrzyjmy się niektórym operacjom na plikach, które oferuje Clojure.
Czytanie zawartości pliku jako całego ciągu
Jeśli chcesz pobrać całą zawartość pliku jako ciąg, możesz użyć rozszerzenia clojure.core.slurpmetoda. Polecenie slurp otwiera czytnik pliku i odczytuje całą jego zawartość, zwracając ciąg.
Poniżej znajduje się przykład, jak można to zrobić.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(def string1 (slurp "Example.txt"))
(println string1))
(Example)
Jeśli plik zawiera następujące wiersze, zostaną one wydrukowane jako -
line : Example1
line : Example2
Czytanie zawartości pliku po jednym wierszu na raz
Jeśli chcesz pobrać całą zawartość pliku jako ciąg po jednym wierszu na raz, możesz użyć rozszerzenia clojure.java.io/readermetoda. Klasa clojure.java.io/reader tworzy bufor czytnika, który jest używany do odczytywania każdej linii pliku.
Poniżej znajduje się przykład, który pokazuje, jak można to zrobić.
(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)
Jeśli plik zawiera następujące wiersze, zostaną one wydrukowane jako -
line : Example1
line : Example2
Dane wyjściowe zostaną pokazane jako -
["line : Example1" "line : Example2"]
Zapisywanie plików „do”
Jeśli chcesz zapisywać pliki „do”, możesz użyć rozszerzenia clojure.core.spitpolecenie, aby wypluć całe ciągi do plików. Polecenie spit jest przeciwieństwem metody slurp. Ta metoda otwiera plik jako autor, zapisuje zawartość, a następnie zamyka plik.
Oto przykład.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(spit "Example.txt"
"This is a string"))
W powyższym przykładzie, jeśli zobaczysz zawartość pliku Example.txt, zobaczysz zawartość „To jest ciąg znaków”.
Zapisywanie plików „do” po jednym wierszu na raz
Jeśli chcesz zapisywać pliki „do” po jednym wierszu na raz, możesz użyć rozszerzenia clojure.java.io.writerklasa. Klasa clojure.java.io.writer służy do tworzenia strumienia zapisującego, w którym bajty danych są wprowadzane do strumienia, a następnie do pliku.
Poniżej znajduje się przykład, który pokazuje, jak można użyć polecenia 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)
Gdy powyższy kod zostanie wykonany, w pliku Example.txt pojawi się wiersz „hello world”. Opcja append: true polega na dołączeniu danych do pliku. Jeśli ta opcja nie jest określona, plik zostanie nadpisany za każdym razem, gdy do pliku zostaną zapisane dane.
Sprawdzanie, czy plik istnieje
Aby sprawdzić, czy plik istnieje, rozszerzenie clojure.java.io.fileclass może służyć do sprawdzania istnienia pliku. Poniżej znajduje się przykład, który pokazuje, jak można to osiągnąć.
(ns clojure.examples.hello
(:gen-class))
;; This program displays Hello World
(defn Example []
(println (.exists (clojure.java.io/file "Example.txt"))))
(Example)
Jeśli plik Example.txt istnieje, dane wyjściowe będą prawdziwe.
Czytanie z konsoli
Aby odczytać dane z konsoli, plik read-linemożna użyć instrukcji. Poniżej znajduje się przykład, który pokazuje, jak można to wykorzystać.
Jeśli wpiszesz komendę (read-line) w oknie REPL, będziesz miał szansę wprowadzić jakieś dane wejściowe w oknie konsoli.
user->(read-line)
Hello World
Powyższy kod wygeneruje następujące dane wyjściowe.
“Hello World”
ZA Stringliterał jest konstruowany w Clojure poprzez umieszczenie tekstu ciągu w cudzysłowie. Ciągi znaków w Clojure należy konstruować przy użyciu podwójnych cudzysłowów, takich jak „Hello World”.
Przykład
Poniżej znajduje się przykład użycia ciągów w Clojure.
(ns clojure.examples.hello
(:gen-class))
(defn hello-world []
(println "Hello World")
(println "This is a demo application"))
(hello-world)
Wynik
Powyższy program generuje następujące dane wyjściowe.
Hello World
This is a demo application
Podstawowe operacje na łańcuchach
Clojure ma wiele operacji, które można wykonać na łańcuchach. Oto operacje.
Sr.No. | Operacje na łańcuchach i opis |
---|---|
1 | str Łączenie ciągów można wykonać za pomocą prostej funkcji str. |
2 | format Formatowanie ciągów można wykonać za pomocą prostej funkcji formatowania. Funkcja formatu formatuje ciąg przy użyciujava.lang.String.format. |
3 | liczyć Zwraca liczbę znaków w ciągu. |
4 | subs Zwraca podłańcuch 's' rozpoczynający się na początku włącznie i kończący się na końcu (domyślnie długość łańcucha), z wyłączeniem. |
5 | porównać Zwraca liczbę ujemną, zero lub liczbę dodatnią, gdy „x” jest logicznie „mniejsze niż”, „równe” lub „większe niż” „y”. |
6 | małe litery Konwertuje ciąg na małe litery. |
7 | duże litery Konwertuje ciąg znaków na wielkie litery. |
8 | Przystąp Zwraca ciąg wszystkich elementów w kolekcji, w postaci zwróconej przez (kolekcja sekwencyjna), oddzielonych opcjonalnym separatorem. |
9 | rozdzielać Dzieli ciąg w wyrażeniu regularnym. |
10 | linie podziału Podzielone ciągi są oparte na znakach zmiany znaczenia \ n lub \ r \ n. |
11 | odwrócić Odwraca znaki w ciągu. |
12 | zastąpić Zamienia wszystkie wystąpienia dopasowania w ciągu na ciąg zastępujący. |
13 | trym Usuwa spacje z obu końców łańcucha. |
14 | triml Usuwa białe znaki z lewej strony ciągu. |
15 | trimr Usuwa białe znaki z prawej strony ciągu. |
Listjest strukturą używaną do przechowywania zbioru elementów danych. W Clojure lista implementujeISeqberło. Listy są tworzone w Clojure przy użyciu funkcji list.
Przykład
Poniżej znajduje się przykład tworzenia listy liczb w Clojure.
(ns clojure.examples.example
(:gen-class))
(defn example []
(println (list 1 2 3 4)))
(example)
Wynik
Powyższy kod daje następujące dane wyjściowe.
(1 2 3 4)
Poniżej znajduje się przykład tworzenia listy postaci w Clojure.
(ns clojure.examples.example
(:gen-class))
(defn example []
(println (list 'a 'b 'c 'd)))
(example)
Powyższy kod daje następujące dane wyjściowe.
(a b c d)
Poniżej przedstawiono listę metod dostępnych w Clojure.
Sr.No. | Listy i opis |
---|---|
1 | lista* Tworzy nową listę zawierającą elementy dołączone do reszty, z których ostatnia będzie traktowana jako sekwencja. |
2 | pierwszy Ta funkcja zwraca pierwszą pozycję na liście. |
3 | n-ty Ta funkcja zwraca pozycję na „n-tej” pozycji na liście. |
4 | Cons Zwraca nową listę, w której element jest dodawany na początek listy. |
5 | spój Zwraca nową listę, w której lista znajduje się na początku, a elementy do dołączenia są umieszczone na końcu. |
6 | odpoczynek Zwraca pozostałe elementy listy po pierwszej pozycji. |
Setsw Clojure to zbiór unikalnych wartości. Zestawy są tworzone w Clojure za pomocą polecenia set.
Przykład
Poniżej znajduje się przykład tworzenia zestawów w Clojure.
(ns clojure.examples.example
(:gen-class))
(defn example []
(println (set '(1 1 2 2))))
(example)
Wynik
Powyższy kod daje następujące dane wyjściowe.
#{1,2}
Poniżej przedstawiono metody dostępne w Clojure dla zestawów.
Sr.No. | Zestawy i opis |
---|---|
1 | zestaw posortowany Zwraca posortowany zestaw elementów. |
2 | dostać Zwraca element w pozycji indeksu. |
3 | zawiera? Sprawdza, czy zestaw zawiera określony element, czy nie. |
4 | spój Dołącza element do zestawu i zwraca nowy zestaw elementów. |
5 | disj Odłącza element od zestawu. |
6 | unia Zwraca zestaw, który jest sumą zestawów wejściowych |
7 | różnica Zwraca zbiór, który jest pierwszym zestawem bez elementów pozostałych zestawów. |
8 | skrzyżowanie Zwraca zestaw będący częścią wspólną zbiorów wejściowych. |
9 | podzbiór? Czy zestaw1 jest podzbiorem zestaw2? |
10 | nadzbiór? Czy zestaw1 jest nadzbiorem zbioru2? |
ZA Vectorto zbiór wartości indeksowanych przez ciągłe liczby całkowite. Wektor jest tworzony za pomocą metody wektorowej w Clojure.
Przykład
Poniżej znajduje się przykład tworzenia wektora w Clojure.
(ns clojure.examples.example
(:require [clojure.set :as set])
(:gen-class))
(defn example []
(println (vector 1 2 3)))
(example)
Wynik
Powyższy kod daje następujące dane wyjściowe.
[1 2 3]
Poniżej przedstawiono metody dostępne w Clojure.
Sr.No. | Wektory i opis |
---|---|
1 | wektor-z Tworzy nowy wektor pojedynczego typu pierwotnego „t”, gdzie „t” jest jednym z następujących: int: long: float: double: byte: short: char lub: boolean. |
2 | n-ty Ta funkcja zwraca element na n-tej pozycji w wektorze. |
3 | dostać Zwraca element w pozycji indeksu w wektorze. |
4 | spój Dołącza element do wektora i zwraca nowy zestaw elementów wektora. |
5 | Muzyka pop W przypadku listy lub kolejki zwraca nową listę / kolejkę bez pierwszego elementu, w przypadku wektora zwraca nowy wektor bez ostatniego elementu. |
6 | subvec Zwraca wektor podrzędny z indeksu początkowego i końcowego. |
ZA Mapto kolekcja, która odwzorowuje klucze na wartości. Dostępne są dwa różne typy map - haszowane i sortowane.HashMaps wymagają kluczy, które poprawnie obsługują hashCode i equals. SortedMaps wymagają kluczy, które implementują porównywalną lub instancję komparatora.
Mapę można utworzyć na dwa sposoby, pierwszy to metoda hash-map.
Tworzenie - HashMaps
HashMapy mają typową relację klucz-wartość i są tworzone za pomocą funkcji mapy skrótów.
(ns clojure.examples.example
(:gen-class))
(defn example []
(def demokeys (hash-map "z" "1" "b" "2" "a" "3"))
(println demokeys))
(example)
Wynik
Powyższy kod daje następujące dane wyjściowe.
{z 1, b 2, a 3}
Tworzenie - SortedMaps
SortedMaps mają unikalną właściwość sortowania swoich elementów w oparciu o kluczowy element. Poniżej znajduje się przykład pokazujący, jak posortowaną mapę można utworzyć za pomocą funkcji sortowanej mapy.
(ns clojure.examples.example
(:gen-class))
(defn example []
(def demokeys (sorted-map "z" "1" "b" "2" "a" "3"))
(println demokeys))
(example)
Powyższy kod daje następujące dane wyjściowe.
{a 3, b 2, z 1}
Z powyższego programu widać wyraźnie, że elementy na mapach są posortowane według wartości klucza. Poniżej przedstawiono metody dostępne dla map.
Sr.No. | Mapy i opis |
---|---|
1 | dostać Zwraca wartość zamapowaną na klucz, nie znaleziono lub nil, jeśli klucz nie jest obecny. |
2 | zawiera? Sprawdź, czy mapa zawiera wymagany klucz. |
3 | odnaleźć Zwraca wpis mapy dla klucza. |
4 | Klucze Zwraca listę kluczy na mapie. |
5 | vals Zwraca listę wartości na mapie. |
6 | dissoc Oddziela wpis wartości klucza od mapy. |
7 | łączyć Łączy dwa wpisy mapy w jeden wpis mapy. |
8 | połączyć z Zwraca mapę składającą się z reszty map połączonych z pierwszą. |
9 | klawisze wyboru Zwraca mapę zawierającą tylko te wpisy w mapie, których klucz znajduje się w kluczach. |
10 | zmień nazwę kluczy Zmienia nazwy kluczy w bieżącej HashMap na nowo zdefiniowane. |
11 | map-invert Odwraca mapy, tak aby wartości stały się kluczami i na odwrót. |
Namespacesw Clojure służą do rozróżniania klas na oddzielne przestrzenie logiczne, tak jak w Javie. Rozważ następujące stwierdzenie.
(:require [clojure.set :as set])
W powyższej instrukcji „clojure.set” jest przestrzenią nazw zawierającą różne klasy i metody używane w programie. Na przykład powyższa przestrzeń nazw zawiera funkcję o nazwie map-invert, która służy do odwracania mapy par klucz-wartość. Nie możemy użyć tej funkcji, chyba że wyraźnie powiemy naszemu programowi, aby zawierał tę przestrzeń nazw.
Przyjrzyjmy się różnym metodom dostępnym dla przestrzeni nazw.
Sr.No. | Metody i opis |
---|---|
1 | * ns * Służy do przeglądania bieżącej przestrzeni nazw. |
2 | ns Służy do tworzenia nowej przestrzeni nazw i kojarzenia jej z uruchomionym programem. |
3 | Alias Dodaj alias z bieżącej przestrzeni nazw do innej przestrzeni nazw. Argumentami są dwa symbole: używany alias i symboliczna nazwa docelowej przestrzeni nazw. |
4 | all-ns Zwraca listę wszystkich przestrzeni nazw. |
5 | find-ns Znajduje i zwraca określoną przestrzeń nazw. |
6 | ns-name Zwraca nazwę określonej przestrzeni nazw. |
7 | aliasy-ns Zwraca aliasy, które są skojarzone z dowolnymi przestrzeniami nazw. |
8 | ns-map Zwraca mapę wszystkich mapowań dla przestrzeni nazw. |
9 | un-alias Zwraca mapę zawierającą tylko te wpisy w mapie, których klucz znajduje się w kluczach. |
Exception handlingjest wymagany w każdym języku programowania do obsługi błędów wykonania, aby można było zachować normalny przepływ aplikacji. Wyjątki zwykle zakłócają normalny przepływ aplikacji, co jest powodem, dla którego musimy używać obsługi wyjątków w naszej aplikacji.
Wyjątek dzieli się ogólnie na następujące kategorie -
Checked Exception- Klasy, które rozszerzają klasę Throwable z wyjątkiem RuntimeException i Error, są nazywane sprawdzanymi wyjątkami. Np. IOException, SQLException, itp. Zaznaczone wyjątki są sprawdzane w czasie kompilacji.
Rozważmy następujący program, który wykonuje operację na pliku o nazwie Example.txt. Jednak zawsze może się zdarzyć, że plik Example.txt nie istnieje.
(ns clojure.examples.example
(:gen-class))
;; This program displays Hello World
(defn Example []
(def string1 (slurp "Example.txt"))
(println string1))
(Example)
Jeśli plik Example.txt nie istnieje, to program wygeneruje następujący wyjątek.
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)
Z powyższego wyjątku wyraźnie widać, że program zgłosił wyjątek FileNotFoundException.
Unchecked Exception- Klasy, które rozszerzają RuntimeException, są znane jako niezaznaczone wyjątki. Na przykład ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException itp. Niezaznaczone wyjątki nie są sprawdzane w czasie kompilacji, ale są sprawdzane w czasie wykonywania.
Jednym z klasycznych przypadków jest wyjątek ArrayIndexOutOfBoundsException, który występuje, gdy próbujesz uzyskać dostęp do indeksu tablicy, który jest większy niż długość tablicy. Oto typowy przykład tego rodzaju błędu.
(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)
Po wykonaniu powyższego kodu zostanie zgłoszony następujący wyjątek.
caught exception: java.lang.ArrayIndexOutOfBoundsException: 5
This is our final block
Let's move on
Błąd
Błąd jest nieodwracalny, np. OutOfMemoryError, VirtualMachineError, AssertionError itp. Są to błędy, z których program nigdy nie może odzyskać i spowodują zawieszenie programu. Potrzebujemy teraz mechanizmu do przechwytywania tych wyjątków, aby program mógł nadal działać, jeśli te wyjątki istnieją.
Poniższy diagram pokazuje, jak zorganizowana jest hierarchia wyjątków w Clojure. Wszystko opiera się na hierarchii zdefiniowanej w Javie.
Łapanie wyjątków
Podobnie jak inne języki programowania, Clojure zapewnia normalny blok „try-catch” do wychwytywania wyjątków w momencie ich wystąpienia.
Poniżej znajduje się ogólna składnia bloku try-catch.
(try
(//Protected code)
catch Exception e1)
(//Catch block)
Cały twój kod, który może zgłosić wyjątek, jest umieszczony w Protected code block.
w catch block, możesz napisać niestandardowy kod do obsługi wyjątku, tak aby aplikacja mogła odzyskać dane po wyjściu.
Spójrzmy na nasz wcześniejszy przykład, który wygenerował wyjątek nie znaleziono pliku i zobaczmy, jak możemy użyć bloku try catch do przechwycenia wyjątku zgłoszonego przez program.
(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)
Powyższy program generuje następujące dane wyjściowe.
caught exception: Example.txt (No such file or directory)
Z powyższego kodu zawijamy błędny kod w try block. W bloku catch po prostu przechwytujemy nasz wyjątek i wyświetlamy komunikat, że wystąpił wyjątek. Mamy więc teraz sensowny sposób przechwytywania wyjątku, który jest generowany przez program.
Wiele bloków połowowych
Można mieć wiele bloków catch do obsługi wielu typów wyjątków. Dla każdego bloku catch, w zależności od typu zgłoszonego wyjątku, możesz napisać kod, aby odpowiednio go obsłużyć.
Zmodyfikujmy nasz wcześniejszy kod, aby zawierał dwa bloki catch, jeden specyficzny dla naszego pliku nie znaleziono wyjątku, a drugi dla ogólnego bloku wyjątków.
(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)
Powyższy program generuje następujące dane wyjściowe.
caught file exception: Example.txt (No such file or directory)
Let's move on
Z powyższego wyniku widać wyraźnie, że nasz wyjątek został przechwycony przez blok catch „FileNotFoundException”, a nie ogólny.
Wreszcie blok
Ostatni blok następuje po bloku try lub bloku catch. Końcowy blok kodu zawsze jest wykonywany, niezależnie od wystąpienia wyjątku.
Korzystanie z bloku last umożliwia uruchamianie dowolnych instrukcji typu czyszczenia, które chcesz wykonać, bez względu na to, co dzieje się w chronionym kodzie. Poniżej znajduje się składnia tego bloku.
(try
(//Protected code)
catch Exception e1)
(//Catch block)
(finally
//Cleanup code)
Zmodyfikujmy powyższy kod i dodajmy ostatni blok kodu. Poniżej znajduje się fragment kodu.
(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)
Powyższy program generuje następujące dane wyjściowe.
caught file exception: Example.txt (No such file or directory)
This is our final block
Let's move on
Z powyższego programu widać, że ostatni blok jest również implementowany po tym, jak blok catch przechwyci wymagany wyjątek.
Ponieważ Clojure wywodzi obsługę wyjątków z języka Java, podobnie jak w Javie, w Clojure dostępne są następujące metody do zarządzania wyjątkami.
public String getMessage()- Zwraca szczegółowy komunikat o wystąpieniu wyjątku. Ta wiadomość jest inicjowana w konstruktorze Throwable.
public Throwable getCause() - Zwraca przyczynę wyjątku reprezentowaną przez obiekt Throwable.
public String toString() - Zwraca nazwę klasy połączoną z wynikiem getMessage ().
public void printStackTrace() - Wyświetla wynik metody toString () wraz ze śladem stosu do System.err, strumienia wyjściowego błędu.
public StackTraceElement [] getStackTrace()- Zwraca tablicę zawierającą każdy element ze śladu stosu. Element pod indeksem 0 reprezentuje górę stosu wywołań, a ostatni element w tablicy reprezentuje metodę na dole stosu wywołań.
public Throwable fillInStackTrace() - Wypełnia ślad stosu tego obiektu Throwable bieżącym śladem stosu, dodając do wszelkich poprzednich informacji w śladzie stosu.
Poniżej znajduje się przykładowy kod wykorzystujący niektóre z metod wymienionych powyżej.
(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)
Powyższy program generuje następujące dane wyjściowe.
caught file exception: java.io.FileNotFoundException: Example.txt (No such file
or directory)
This is our final block
Let's move on
Sequences są tworzone za pomocą ‘seq’Komenda. Poniżej znajduje się prosty przykład tworzenia sekwencji.
(ns clojure.examples.example
(:gen-class))
;; This program displays Hello World
(defn Example []
(println (seq [1 2 3])))
(Example)
Powyższy program generuje następujące dane wyjściowe.
(1 2 3)
Poniżej przedstawiono różne metody dostępne dla sekwencji.
Sr.No. | Metody i opis |
---|---|
1 | Cons Zwraca nową sekwencję, w której „x” jest pierwszym elementem, a „seq” resztą. |
2 | spój Zwraca nową sekwencję, w której „x” jest elementem dodawanym na końcu sekwencji. |
3 | concat Służy do łączenia dwóch sekwencji razem. |
4 | odrębny Służy tylko do zapewnienia, że do sekwencji zostaną dodane różne elementy. |
5 | odwrócić Odwraca elementy w sekwencji. |
6 | pierwszy Zwraca pierwszy element sekwencji. |
7 | ostatni, ubiegły, zeszły Zwraca ostatni element sekwencji. |
8 | odpoczynek Zwraca całą sekwencję z wyjątkiem pierwszego elementu. |
9 | sortować Zwraca posortowaną sekwencję elementów. |
10 | upuszczać Usuwa elementy z sekwencji na podstawie liczby elementów, które należy usunąć. |
11 | ostatni Pobiera ostatnią listę elementów z sekwencji. |
12 | brać Pobiera pierwszą listę elementów z sekwencji. |
13 | podzielone Dzieli sekwencję elementów na dwie części. Określono miejsce, w którym powinien nastąpić podział. |
ZA regular expressionto wzorzec używany do wyszukiwania podciągów w tekście. Wyrażenia regularne są używane w różnych językach programowania i często używane w językach programowania typu LISP.
Poniżej znajduje się przykład wyrażenia regularnego.
//d+
Powyższe wyrażenie regularne służy do znalezienia jeszcze jednego wystąpienia cyfry w ciągu. Znaki // są używane, aby zapewnić, że znaki „d” i „+” są używane do reprezentowania wyrażenia regularnego.
Ogólnie wyrażenia regularne działają z następującym zestawem reguł.
Istnieją dwa specjalne znaki pozycyjne, które służą do oznaczenia początku i końca linii: daszek (∧) i znak dolara ($):
Wyrażenia regularne mogą również zawierać kwantyfikatory. Znak plus (+) reprezentuje jeden lub więcej razy, zastosowany do poprzedniego elementu wyrażenia. Gwiazdka (*) oznacza zero lub więcej wystąpień. Znak zapytania (?) Oznacza zero lub raz.
Metaznak {i} służy do dopasowania określonej liczby wystąpień poprzedniego znaku.
W wyrażeniu regularnym kropka (.) Może reprezentować dowolny znak. Jest to opisane jako znak wieloznaczny.
Wyrażenie regularne może zawierać klasy znaków. Zestaw znaków można podać jako prostą sekwencję znaków zawartą w metaznaki [i], jak w [aeiou]. W przypadku zakresów liter lub cyfr można użyć separatora myślnika, takiego jak [a – z] lub [a – mA – M]. Uzupełnienie klasy znaków jest oznaczone wiodącym daszkiem w nawiasach kwadratowych, jak w [∧a – z] i reprezentuje wszystkie znaki inne niż określone.
W przypadku wyrażeń regularnych dostępne są następujące metody.
Sr.No. | Metody i opis |
---|---|
1 | zmiana wzoru Zwraca instancję java.util.regex.Pattern. Jest to następnie używane w dalszych metodach dopasowywania wzorców. |
2 | refind Zwraca następne dopasowanie wyrażenia regularnego, jeśli istnieje, łańcucha do wzorca, używając java.util.regex.Matcher.find () |
3 | zastąpić Funkcja replace służy do zastępowania podciągu w ciągu nową wartością ciągu. Poszukiwanie podciągu odbywa się za pomocą wzorca. |
4 | Zastąp najpierw Funkcja replace służy do zamiany podciągu w ciągu na nową wartość ciągu, ale tylko przy pierwszym wystąpieniu podciągu. Poszukiwanie podciągu odbywa się za pomocą wzorca. |
Predicatesto funkcje, które oceniają warunek i podają wartość true lub false. Funkcje predykatów widzieliśmy w przykładach rozdziału poświęconego liczbom. Widzieliśmy funkcje takie jak „nawet?” który jest używany do sprawdzania, czy liczba jest parzysta, czy nie, lub „neg”? który jest używany do sprawdzania, czy liczba jest większa od zera, czy nie. Wszystkie te funkcje zwracają wartość true lub false.
Poniżej znajduje się przykład predykatów w 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)
Powyższy program generuje następujące dane wyjściowe.
true
false
true
true
Oprócz zwykłych funkcji predykatów Clojure udostępnia więcej funkcji dla predykatów. W przypadku predykatów dostępne są następujące metody.
Sr.No. | Metody i opis |
---|---|
1 | każdy pred Pobiera zestaw predykatów i zwraca funkcję `` f '', która zwraca prawdę, jeśli wszystkie jej predykaty składające zwracają logiczną wartość true dla wszystkich argumentów, w przeciwnym razie zwraca fałsz. |
2 | każdy? Zwraca prawdę, jeśli predykat jest prawdziwy dla każdej wartości, w przeciwnym razie fałsz. |
3 | trochę Zwraca pierwszą logiczną wartość prawdziwą dla dowolnej wartości predykatu x w zbiorze wartości. |
4 | nie-żaden? Zwraca wartość false, jeśli którykolwiek z predykatów wartości w kolekcji jest logicznie prawdziwy, w przeciwnym razie prawda. |
Destructuring to funkcjonalność Clojure, która pozwala wyodrębnić wartości ze struktury danych, takiej jak wektor, i powiązać je z symbolami bez konieczności jawnego przechodzenia przez strukturę danych.
Spójrzmy na przykład, co dokładnie oznacza Destrukturyzacja i jak to się dzieje.
Przykład
(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)
Powyższy program generuje następujące dane wyjściowe.
Wynik
1 2 3 4
W powyższym przykładzie należy zwrócić uwagę na:
Definiujemy wektor liczb całkowitych jako 1, 2, 3 i 4.
Używamy wtedy ‘let’ instrukcja, aby przypisać 4 zmienne (a, b, c i d) bezpośrednio do zmiennej my-vector.
Jeśli uruchomimy ‘println’ na czterech zmiennych, widzimy, że zostały one już przypisane odpowiednio do wartości w wektorze.
Więc clojure zniszczył zmienną my-vector, która ma cztery wartości, kiedy została przypisana za pomocą instrukcji „let”. Zdekonstruowane cztery wartości zostały następnie odpowiednio przypisane do czterech parametrów.
Jeśli istnieją dodatkowe zmienne, które nie mają odpowiedniej wartości, do której można je przypisać, wówczas zostanie im przypisana wartość nil. Poniższy przykład wyjaśnia tę kwestię.
Przykład
(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)
Powyższy program generuje następujące dane wyjściowe. Na podstawie wyników widać, że skoro ostatnia zmienna „e” nie ma odpowiadającej wartości w wektorze, odpowiada zeru.
Wynik
1 2 3 4 nil
reszta
Zmienna „the-rest” służy do przechowywania pozostałych wartości, których nie można przypisać do żadnej zmiennej.
Przykład tego, jak jest używany, pokazano w poniższym programie.
Przykład
(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)
Powyższy program generuje następujące dane wyjściowe. Na podstawie wyników widać wyraźnie, że wartości 3 i 4 nie mogą być przypisane do żadnej zmiennej, więc są przypisywane do zmiennej „reszta”.
Wynik
1 2 (3 4)
Mapy zniszczenia
Podobnie jak wektory, mapy mogą zostać zniszczone. Poniżej znajduje się przykład tego, jak można to osiągnąć.
Przykład
(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)
Powyższy program generuje następujące dane wyjściowe. Z programu jasno widać, że wartości map „a” i „b” są przypisane do zmiennych a i b.
Wynik
1 2
Podobnie w przypadku wektorów, jeśli nie ma odpowiedniej wartości na mapie, gdy nastąpi destrukturyzacja, wówczas zmiennej zostanie przypisana wartość zero.
Oto przykład.
Przykład
(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)
Powyższy program generuje następujące dane wyjściowe.
Wynik
1 2 nil
Ponieważ framework Clojure wywodzi się z klas Java, można używać klas daty i czasu dostępnych w Javie w Clojure. Plikclass date reprezentuje określoną chwilę w czasie z dokładnością do milisekund.
Poniżej przedstawiono metody dostępne dla klasy daty i godziny.
java.util.Date
Służy do tworzenia obiektu daty w Clojure.
Składnia
Poniżej znajduje się składnia.
java.util.Date.
Parameters - Żaden.
Return Value - Alokuje obiekt Date i inicjuje go tak, aby reprezentował czas, w którym został przydzielony, mierzony z dokładnością do najbliższej milisekundy.
Przykład
Przykład tego, jak jest używany, pokazano w poniższym programie.
(ns example)
(defn Example []
(def date (.toString (java.util.Date.)))
(println date))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe. Zależy to od aktualnej daty i godziny w systemie, w którym program jest uruchamiany.
Tue Mar 01 06:11:17 UTC 2016
java.text.SimpleDateFormat
Służy do formatowania danych wyjściowych.
Składnia
Poniżej znajduje się składnia.
(java.text.SimpleDateFormat. format dt)
Parameters- „format” to format, który ma być użyty podczas formatowania daty. „dt” to data, którą należy sformatować.
Return Value - Wyjście sformatowanej daty.
Przykład
Przykład tego, jak jest używany, pokazano w poniższym programie.
(ns example)
(defn Example []
(def date (.format (java.text.SimpleDateFormat. "MM/dd/yyyy") (new java.util.Date)))
(println date))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe. Zależy to od aktualnej daty i godziny w systemie, w którym program jest uruchamiany.
03/01/2016
uzyskać czas
Zwraca liczbę milisekund od 1 stycznia 1970 00:00:00 czasu GMT reprezentowanych przez ten obiekt Date.
Składnia
Poniżej znajduje się składnia.
(.getTime)
Parameters - Żaden.
Return Value - Liczba milisekund od 1 stycznia 1970 r. 00:00:00 czasu GMT reprezentowana przez tę datę.
Przykład
Przykład tego, jak jest używany, pokazano w poniższym programie.
(ns example)
(import java.util.Date)
(defn Example []
(def date (.getTime (java.util.Date.)))
(println date))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe. Zależy to od aktualnej daty i godziny w systemie, w którym program jest uruchamiany.
1456812778160
Atomsto typ danych w Clojure, który umożliwia zarządzanie współdzielonym, synchronicznym, niezależnym stanem. Atom jest taki sam, jak każdy typ referencyjny w każdym innym języku programowania. Podstawowym zastosowaniem atomu jest przechowywanie niezmiennych struktur danych Clojure. Wartość posiadana przez atom zmienia się za pomocąswap! method.
Wewnętrznie zamień! odczytuje bieżącą wartość, stosuje do niej funkcję i próbuje ją porównać i ustawić. Ponieważ inny wątek mógł zmienić wartość w międzyczasie, może być zmuszony do ponownej próby i robi to w pętli spinowej. Efektem netto jest to, że wartość zawsze będzie wynikiem zastosowania dostarczonej funkcji do wartości bieżącej, atomowo.
Przykład
Atomy tworzone są za pomocą metody atomowej. Przykład tego samego pokazano w poniższym programie.
(ns clojure.examples.example
(:gen-class))
(defn example []
(def myatom (atom 1))
(println @myatom))
(example)
Wynik
Powyższy program daje następujący wynik.
1
Dostęp do wartości atomu uzyskuje się za pomocą symbolu @. Clojure ma kilka operacji, które można wykonać na atomach. Oto operacje.
Sr.No. | Operacje i opis |
---|---|
1 | Resetowanie! Ustawia wartość atom na nową wartość bez względu na bieżącą wartość. |
2 | porównaj i ustaw! Atomowo ustawia wartość atom na nową wartość wtedy i tylko wtedy, gdy aktualna wartość atomu jest identyczna ze starą wartością posiadaną przez atom. Zwraca true, jeśli dzieje się set, w przeciwnym razie zwraca false. |
3 | zamiana! Atomowo zamienia wartość atomu na nową na podstawie określonej funkcji. |
W Clojure, metadatasłuży do oznaczania danych w kolekcji lub do danych przechowywanych w symbolu. Zwykle służy do dodawania adnotacji do danych o typach do bazowego kompilatora, ale może być również używany przez programistów. Metadane nie są traktowane jako część wartości obiektu. Jednocześnie metadane są niezmienne.
Następujące operacje są możliwe w Clojure w odniesieniu do metadanych.
Sr.No. | Operacje i opis |
---|---|
1 | meta-z Ta funkcja służy do definiowania mapy metadanych dla dowolnego obiektu. |
2 | meta Ta funkcja służy do sprawdzania, czy jakiekolwiek metadane są powiązane z obiektem. |
3 | var-meta Zwraca obiekt tego samego typu i wartości co oryginalny obiekt, ale z połączonymi metadanymi. |
StructMapssłużą do tworzenia struktur w Clojure. Na przykład, jeśli chcesz utworzyć strukturę składającą się z nazwy pracownika i identyfikatora pracownika, możesz to zrobić za pomocą StructMaps.
Następujące operacje są możliwe w Clojure w odniesieniu do StructMaps.
Sr.No. | Operacje i opis |
---|---|
1 | defstruct Ta funkcja służy do definiowania wymaganej konstrukcji. |
2 | struct Ta funkcja służy do definiowania obiektu struktury typu, który jest tworzony przez operację defstruct. |
3 | struct-map Ta funkcja jest używana do przypisywania wartości kluczowym wartościom poprzez jawne definiowanie, które wartości są przypisywane do których kluczy w strukturze. |
4 | Dostęp do poszczególnych pól Dostęp do poszczególnych pól struktury można uzyskać, uzyskując dostęp do kluczy wraz z obiektem struktury. |
5 | Niezmienna natura Domyślnie struktury są również niezmienne, więc jeśli spróbujemy zmienić wartość konkretnego klucza, to się nie zmieni. |
6 | Dodawanie nowego klucza do struktury Ponieważ struktury są niezmienne, jedynym sposobem na dodanie kolejnego klucza do struktury jest utworzenie nowej struktury. Przykład tego, jak można to osiągnąć, przedstawiono w poniższym programie. |
Jak wielokrotnie wskazywano, Clojure jest językiem programowania, w którym wiele typów danych jest niezmiennych, co oznacza, że jedynym sposobem zmiany wartości zmiennej jest utworzenie nowej zmiennej i przypisanie jej nowej wartości. Jednak Clojure zapewnia pewne elementy, które mogą tworzyć zmienny stan. Widzieliśmy, że można to osiągnąć za pomocą typu danych atom. Innym sposobem, w jaki można to osiągnąć, są agenci.
Agentszapewniają niezależną, asynchroniczną zmianę poszczególnych lokalizacji. Agenci są przywiązani do jednego miejsca przechowywania przez cały czas ich życia i pozwalają tylko na mutację tej lokalizacji (do nowego stanu) w wyniku działania. Akcje to funkcje (opcjonalnie z dodatkowymi argumentami), które są asynchronicznie stosowane do stanu agenta i których wartość zwracana staje się nowym stanem agenta.
Następujące operacje są możliwe w Clojure w odniesieniu do agentów.
Sr.No. | Operacje i opis |
---|---|
1 | agent Agent jest tworzony za pomocą komendy agent. |
2 | wysłać Ta funkcja służy do wysyłania wartości do agenta. |
3 | agenci zamykania Ta funkcja służy do zamykania wszystkich działających agentów. |
4 | odesłać Istnieją przypadki, w których agent ma przypisaną funkcję, która ma charakter blokujący. |
5 | czekaj na Ponieważ aktualizacja wartości agenta jest opóźniona, Clojure udostępnił funkcję „czekaj na”, która służy do określania czasu w milisekundach oczekiwania na aktualizację agenta. |
6 | czekać na Blokuje bieżący wątek (na czas nieokreślony!) Do momentu wykonania wszystkich akcji wysłanych do tej pory z tego wątku lub agenta do agentów. Blokuje na nieudanych agentach. |
7 | błąd agenta Zwraca wyjątek zgłoszony podczas asynchronicznej akcji agenta, jeśli agent zawiedzie. Zwraca nil, jeśli agent nie zawiedzie. |
Watcherssą funkcjami dodanymi do typów zmiennych, takich jak atomy i zmienne referencyjne, które są wywoływane, gdy zmienia się wartość typu zmiennej. Na przykład, jeśli program wywołujący zmieni wartość zmiennej atom, a funkcja obserwatora jest dołączona do zmiennej atom, funkcja zostanie wywołana natychmiast po zmianie wartości atomu.
Następujące funkcje są dostępne w Clojure for Watchers.
dodaj zegarek
Dodaje funkcję obserwującą do odwołania agenta / atom / var / ref. Zegarek‘fn’musi być „fn” z 4 argumentami: klucz, odniesienie, jego stary stan, jego nowy stan. Za każdym razem, gdy stan odniesienia mógł zostać zmieniony, wszystkie zarejestrowane zegarki będą miały wywoływane funkcje.
Składnia
Poniżej znajduje się składnia.
(add-watch variable :watcher
(fn [key variable-type old-state new-state]))
Parameters- „zmienna” to nazwa atomu lub zmiennej odniesienia. „typ zmiennej” to typ zmiennej, atom lub zmienna odniesienia. „stary stan i nowy stan” to parametry, które automatycznie przechowują starą i nową wartość zmiennej. „klucz” musi być niepowtarzalny w odniesieniu do numeru referencyjnego i może służyć do usuwania zegarka za pomocą funkcji usuwania zegarka.
Return Value - Żaden.
Przykład
Przykład tego, jak jest używany, pokazano w poniższym programie.
(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)
Wynik
Powyższy program generuje następujące dane wyjściowe.
The value of the atom has been changed
old-state 0
new-state 2
usuń zegarek
Usuwa zegarek, który został dołączony do zmiennej odniesienia.
Składnia
Poniżej znajduje się składnia.
(remove-watch variable watchname)
Parameters- „zmienna” to nazwa atomu lub zmiennej odniesienia. „nazwa zegarka” to nazwa nadana zegarkowi podczas definiowania funkcji zegarka.
Return Value - Żaden.
Przykład
Przykład tego, jak jest używany, pokazano w poniższym programie.
(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)
Wynik
Powyższy program generuje następujące dane wyjściowe.
The value of the atom has been changed
old-state 0
new-state 2
Z powyższego programu jasno widać, że drugie polecenie resetowania nie uruchamia obserwatora, ponieważ zostało usunięte z listy obserwatorów.
W dowolnym języku Macrossłużą do generowania kodu wbudowanego. Clojure nie jest wyjątkiem i zapewnia programistom proste funkcje makr. Makra są używane do pisania procedur generowania kodu, które zapewniają programiście potężny sposób dostosowania języka do potrzeb programisty.
Poniżej przedstawiono metody dostępne dla makr.
defmacro
Ta funkcja służy do definiowania makra. Makro będzie miało nazwę makra, listę parametrów i treść makra.
Składnia
Poniżej znajduje się składnia.
(defmacro name [params*] body)
Parameters- „nazwa” to nazwa makra. „params” to parametry przypisane do makra. „body” to treść makra.
Return Value - Żaden.
Przykład
Przykład tego, jak jest używany, pokazano w poniższym programie.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(defmacro Simple []
(println "Hello"))
(macroexpand '(Simple)))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe.
Hello
Z powyższego programu widać, że makro „Simple” jest rozwijane w linii do „println” „Hello”. Makra są podobne do funkcji, z tą różnicą, że argumenty formularza są oceniane w przypadku makr.
makro-rozwinąć
Służy do rozwijania makra i umieszczania kodu w programie.
Składnia
Poniżej znajduje się składnia.
(macroexpand macroname)
Parameters - „nazwa_makra” to nazwa makra, które ma zostać rozszerzone.
Return Value - Rozszerzone makro.
Przykład
Przykład tego, jak jest używany, pokazano w poniższym programie.
(ns clojure.examples.example
(:gen-class))
(defn Example []
(defmacro Simple []
(println "Hello"))
(macroexpand '(Simple)))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe.
Hello
Makro z argumentami
Makra mogą być również używane do przyjmowania argumentów. Makro może przyjmować dowolną liczbę argumentów. Poniższy przykład pokazuje, jak można używać argumentów.
Przykład
(ns clojure.examples.example
(:gen-class))
(defn Example []
(defmacro Simple [arg]
(list 2 arg))
(println (macroexpand '(Simple 2))))
(Example)
Powyższy przykład umieszcza argument w makrze Simple, a następnie używa tego argumentu, aby dodać wartość argumentu do listy.
Wynik
Powyższy program generuje następujące dane wyjściowe.
(2 2)
Reference valuesto kolejny sposób, w jaki Clojure może pracować z żądaniem posiadania zmiennych zmiennych. Clojure zapewnia zmienne typy danych, takie jak atomy, agenci i typy referencyjne.
Poniżej przedstawiono operacje dostępne dla wartości odniesienia.
Sr.No. | Operacje i opis |
---|---|
1 | ref Służy do tworzenia wartości odniesienia. Podczas tworzenia wartości referencyjnej istnieje możliwość udostępnienia funkcji walidatora, która zweryfikuje utworzoną wartość. |
2 | zestaw ref Ta funkcja służy do ustawiania wartości odniesienia na nową wartość, niezależnie od tego, jaka jest starsza wartość. |
3 | zmieniać Ta funkcja służy do zmiany wartości typu referencyjnego, ale w bezpieczny sposób. Jest to uruchamiane w wątku, do którego nie ma dostępu inny proces. |
4 | dosync Uruchamia wyrażenie (w niejawnym do) w transakcji, która obejmuje wyrażenie i wszelkie zagnieżdżone wywołania. |
5 | łagodzić Commute jest również używany do zmiany wartości typu odwołania, podobnie jak alter i ref-set. |
Aby móc korzystać z funkcji bazy danych, należy najpierw pobrać plik jdbc files z następującego adresu URL - https://codeload.github.com/clojure/java.jdbc/zip/master
Znajdziesz plik zip, który zawiera niezbędne sterowniki dla Clojure, aby mieć możliwość łączenia się z bazami danych. Po rozpakowaniu pliku zip dodaj rozpakowaną lokalizację do ścieżki klas.
Głównym plikiem służącym do połączeń z bazą danych jest plik o nazwie jdbc.clj w lokalizacji clojure / java.
Łącznik clojure jdbc obsługuje wiele różnych baz danych, z których niektóre są następujące.
- H2Database
- Oracle
- Microsoft SQL Server
- MySQL
- PostgreSQL
W naszym przykładzie użyjemy MySQL DB jako przykładu.
Następujące operacje są możliwe w Clojure w odniesieniu do baz danych.
Połączenie z bazą danych
Przed połączeniem się z bazą danych MySQL upewnij się, że:
Utworzyłeś bazę danych TESTDB.
Utworzyłeś tabelę PRACOWNIK w TESTDB.
Ta tabela zawiera pola FIRST_NAME, LAST_NAME, AGE, SEX i INCOME.
ID użytkownika „testuser” i hasło „test123” są ustawione na dostęp do bazy danych TESTDB.
Upewnij się, że pobrałeś „plik jar mysql” i dodałeś go do ścieżki klas.
Przeszedłeś przez samouczek MySQL, aby zrozumieć podstawy MySQL .
Składnia
Poniżej znajduje się składnia tworzenia połączenia w Clojure.
(def connection_name {
:subprotocol “protocol_name”
:subname “Location of mysql DB”
:user “username” :password “password” })
Parameters- „nazwa_połączenia” to nazwa, która ma być nadana połączeniu. Protokół podrzędny jest protokołem używanym do połączenia. Domyślnie będziemy używać protokołu mysql. „nazwa podrzędna” to adres URL połączenia z bazą danych mysql wraz z nazwą bazy danych. „user” to nazwa użytkownika używana do łączenia się z bazą danych. „hasło” to hasło używane do łączenia się z bazą danych.
Return Value - Zapewni to ciąg połączenia, którego można użyć w kolejnych operacjach mysql.
Poniższy przykład pokazuje, jak połączyć się z tabelami w schemacie informacji i pobrać wszystkie dane w tabeli.
Przykład
(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)))
Zapytanie o dane
Zapytanie o dane w dowolnej bazie danych oznacza pobranie przydatnych informacji z bazy danych. Po ustanowieniu połączenia z bazą danych możesz wykonać zapytanie do tej bazy danych. Poniżej znajduje się składnia, za pomocą której można wyszukiwać dane za pomocą Clojure.
Składnia
clojure.java.jdbc/query dbconn
["query"]
:row-fn :sequence
Parameters- „dbconn” to nazwa połączenia używanego do łączenia się z bazą danych. „zapytanie” to ciąg zapytania używany do pobierania danych z bazy danych. „: sequence” to domyślnie wszystkie wiersze danych pobrane z bazy danych i zwracane jako sekwencja. Następnie można wykonać niezbędne operacje na sekwencji, aby zobaczyć, jakie dane zostały pobrane.
Return Value - Zwróci sekwencję, która będzie zawierała wiersze danych z operacji zapytania.
Poniższy przykład pokazuje, jak połączyć się z tabelą pracowników i pobrać kolumnę first_name z wierszy w tabeli.
Przykład
(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)))
Z powyższego kodu możemy to zobaczyć
Zapytanie „wybierz imię od pracownika” jest przekazywane jako ciąg zapytania.
The: first_name to sekwencja, która jest zwracana w wyniku operacji pobierania.
Jeśli założymy, że w naszej bazie danych jest tylko jeden wiersz zawierający wartość imię_nazwa Johna, następujące wyniki będą wynikiem powyższego programu.
(John)
Wstawianie danych
Jest to wymagane, gdy chcesz utworzyć rekordy w tabeli bazy danych. Poniżej znajduje się składnia, za pomocą której można wstawiać dane za pomocą Clojure. Odbywa się to za pomocą‘insert!’ funkcjonować.
Składnia
clojure.java.jdbc/insert!
:table_name {:column_namen columnvalue}
Parameters- „: nazwa_tabeli” to nazwa tabeli, do której należy dokonać wstawienia. „{: column_namen columnvalue}” to mapa wszystkich nazw kolumn i wartości, które należy dodać jako wiersz w tabeli.
Return Value - Zwróci zero, jeśli wstawienie zakończy się pomyślnie.
Poniższy przykład pokazuje, jak wstawić rekord do tabeli pracowników w bazie danych testdb.
Przykład
(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}))
Jeśli teraz sprawdzisz swoją bazę danych MySQL i tabelę pracowników, zobaczysz, że powyższy wiersz zostanie pomyślnie wstawiony do tabeli.
Usuwanie danych
Wiersze można usunąć z tabeli przy użyciu rozszerzenia ‘delete!’funkcjonować. Poniżej znajduje się składnia opisująca, jak można wykonać tę operację.
Składnia
clojure.java.jdbc/delete!
:table_name [condition]
Parameters- „: nazwa_tabeli” to nazwa tabeli, do której należy dokonać wstawienia. „warunek” to warunek służący do określenia, który wiersz należy usunąć z tabeli.
Return Value - Zwróci liczbę usuniętych wierszy.
Poniższy przykład pokazuje, jak usunąć rekord z tabeli pracowników w bazie danych testdb. Przykład usuwa wiersz z tabeli na podstawie warunku, że wiek jest równy 30.
Przykład
(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])))
Jeśli miałeś rekord, który miał wiersz z wiekiem równym 30, ten wiersz zostanie usunięty.
Aktualizacja danych
Wiersze można aktualizować z tabeli przy użyciu rozszerzenia ‘update!’funkcjonować. Poniżej znajduje się składnia opisująca, jak można wykonać tę operację.
Składnia
clojure.java.jdbc/update!
:table_name
{setcondition}
[condition]
Parameters- „: nazwa_tabeli” to nazwa tabeli, do której należy dokonać wstawienia. „setcondition” to kolumna, która wymaga aktualizacji zgodnie z mapą. „warunek” to warunek, który służy do określenia, który wiersz ma zostać usunięty z tabeli.
Return Value - Zwróci liczbę zaktualizowanych wierszy.
Poniższy przykład pokazuje, jak usunąć rekord z tabeli pracowników w bazie danych testdb. Przykład aktualizuje wiersz z tabeli na podstawie warunku, że wiek jest równy 30 i aktualizuje wartość dochodu do 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])))
Jeśli miałeś rekord, który miał wiersz z wiekiem równym 30, ten wiersz zostanie zaktualizowany, a wartość dochodu zostanie ustawiona na 40.
Transakcje
Transakcje to mechanizmy zapewniające spójność danych. Transakcje mają następujące cztery właściwości -
Atomicity - Albo transakcja zostaje zakończona, albo nic się nie dzieje.
Consistency - Transakcja musi rozpocząć się w stanie zgodnym i pozostawić system w stanie zgodnym.
Isolation - Pośrednie wyniki transakcji nie są widoczne poza bieżącą transakcją.
Durability - Po zatwierdzeniu transakcji efekty są trwałe, nawet po awarii systemu.
Przykład
Poniższy przykład pokazuje, jak implementować transakcje w Clojure. Wszelkie operacje, które należy wykonać w transakcji, muszą być osadzone w pliku‘with-dbtransaction’ klauzula.
(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])))
Jak już wiemy, kod Clojure działa na końcu w wirtualnym środowisku Java. Dlatego ma sens tylko to, że Clojure jest w stanie wykorzystać wszystkie funkcje Java. W tym rozdziale omówimy korelację między Clojure a Javą.
Wywołanie metod Java
Metody Java można wywołać przy użyciu notacji kropkowej. Przykładem są stringi. Ponieważ wszystkie ciągi w Clojure są i tak napisami Java, możesz wywoływać zwykłe metody Java na łańcuchach.
Przykład tego, jak to się robi, przedstawiono w poniższym programie.
Przykład
(ns Project
(:gen-class))
(defn Example []
(println (.toUpperCase "Hello World")))
(Example)
Powyższy program generuje następujące dane wyjściowe. Z kodu widać, że jeśli wywołasz po prostu notację kropkową dla dowolnej metody łańcuchowej, zadziała ona również w Clojure.
Wynik
HELLO WORLD
Wywołanie metod Java z parametrami
Możesz także wywołać metody Java z parametrami. Przykład tego, jak to się robi, przedstawiono w poniższym programie.
Przykład
(ns Project
(:gen-class))
(defn Example []
(println (.indexOf "Hello World","e")))
(Example)
Powyższy program generuje następujące dane wyjściowe. Z powyższego kodu widać, że przekazujemy parametr „e” do metody indexOf. Powyższy program generuje następujące dane wyjściowe.
Wynik
1
Tworzenie obiektów Java
Obiekty można tworzyć w Clojure za pomocą słowa kluczowego „new”, podobnie jak w Javie.
Przykład tego, jak to się robi, przedstawiono w poniższym programie.
Przykład
(ns Project
(:gen-class))
(defn Example []
(def str1 (new String "Hello"))
(println str1))
(Example)
Powyższy program generuje następujące dane wyjściowe. Z powyższego kodu widać, że możemy użyć słowa kluczowego „new”, aby utworzyć nowy obiekt z istniejącej klasy String w Javie. Możemy przekazać wartość podczas tworzenia obiektu, tak jak robimy to w Javie. Powyższy program generuje następujące dane wyjściowe.
Wynik
Hello
Poniżej znajduje się kolejny przykład, który pokazuje, jak możemy stworzyć obiekt klasy Integer i użyć go w zwykłych poleceniach Clojure.
Przykład
(ns Project
(:gen-class))
(defn Example []
(def my-int(new Integer 1))
(println (+ 2 my-int)))
(Example)
Powyższy program generuje następujące dane wyjściowe.
Wynik
3
Polecenie importu
Możemy również użyć polecenia importu, aby dołączyć biblioteki Java do przestrzeni nazw, aby zapewnić łatwy dostęp do klas i metod.
Poniższy przykład pokazuje, jak możemy użyć polecenia importu. W przykładzie używamy polecenia import, aby zaimportować klasy z plikujava.util.stackbiblioteka. Następnie możemy użyć metody push i pop klasy stosu w takiej postaci, w jakiej są.
Przykład
(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)
Powyższy program generuje następujące dane wyjściowe.
Wynik
First Element
Uruchamianie kodu za pomocą polecenia Java
Kod Clojure można uruchomić za pomocą polecenia Java. Poniżej znajduje się składnia pokazująca, jak można to zrobić.
java -jar clojure-1.2.0.jar -i main.clj
Musisz wspomnieć o pliku jar Clojure, aby wszystkie klasy oparte na Clojure zostały załadowane do JVM. Plik „main.clj” jest plikiem kodu Clojure, który należy wykonać.
Wbudowane funkcje Java
Clojure może korzystać z wielu wbudowanych funkcji języka Java. Niektóre z nich to -
Math PI function- Clojure może użyć metody Math do wartości PI. Poniżej znajduje się przykładowy kod.
Przykład
(ns Project
(:gen-class))
(defn Example []
(println (. Math PI)))
(Example)
Powyższy kod daje następujące dane wyjściowe.
Wynik
3.141592653589793
System Properties- Clojure może również sprawdzać właściwości systemu. Poniżej znajduje się przykładowy kod.
Przykład
(ns Project
(:gen-class))
(defn Example []
(println (.. System getProperties (get "java.version"))))
(Example)
W zależności od wersji oprogramowania Java w systemie zostanie wyświetlona odpowiednia wartość. Poniżej przedstawiono przykładowe dane wyjściowe.
Wynik
1.8.0_45
W programowaniu Clojure większość typów danych jest niezmienna, więc jeśli chodzi o programowanie współbieżne, kod wykorzystujący te typy danych jest dość bezpieczny, gdy kod działa na wielu procesorach. Jednak często istnieje wymóg współdzielenia danych, a jeśli chodzi o udostępnianie danych na wielu procesorach, konieczne staje się zapewnienie, że stan danych jest utrzymywany pod względem integralności podczas pracy z wieloma procesorami. Jest to znane jakoconcurrent programming Clojure zapewnia wsparcie dla takiego programowania.
System pamięci transakcyjnej oprogramowania (STM), udostępniany poprzez dosync, ref, set, alter, itp. Obsługuje współdzielenie zmieniającego się stanu między wątkami w sposób synchroniczny i skoordynowany. System agenta obsługuje współdzielenie zmieniającego się stanu między wątkami w sposób asynchroniczny i niezależny. System atomów obsługuje współdzielenie zmieniającego się stanu między wątkami w sposób synchroniczny i niezależny. Podczas gdy dynamiczny system var, udostępniany przez def, bind, itp., Wspiera izolowanie zmieniającego się stanu w wątkach.
Inne języki programowania również podążają za modelem programowania współbieżnego.
Mają bezpośrednie odniesienie do danych, które można zmienić.
Jeśli wymagany jest dostęp współdzielony, obiekt jest blokowany, wartość jest zmieniana, a proces jest kontynuowany do następnego dostępu do tej wartości.
W Clojure nie ma blokad, ale pośrednie odniesienia do niezmiennych trwałych struktur danych.
W Clojure istnieją trzy typy odniesień.
Vars - Zmiany są izolowane w wątkach.
Refs - Zmiany są synchronizowane i koordynowane między wątkami.
Agents - Obejmuje asynchroniczne, niezależne zmiany między wątkami.
Następujące operacje są możliwe w Clojure w odniesieniu do programowania współbieżnego.
Transakcje
Współbieżność w Clojure opiera się na transakcjach. Referencje można zmieniać tylko w ramach transakcji. W transakcjach obowiązują następujące zasady.
- Wszystkie zmiany są atomowe i izolowane.
- Każda zmiana odniesienia ma miejsce w transakcji.
- Żadna transakcja nie widzi skutku innej transakcji.
- Wszystkie transakcje są umieszczane wewnątrz bloku dosync.
Widzieliśmy już, co robi blok dosync, spójrzmy na to ponownie.
dosync
Uruchamia wyrażenie (w niejawnym do) w transakcji, która obejmuje wyrażenie i wszelkie zagnieżdżone wywołania. Rozpoczyna transakcję, jeśli żadna nie jest już uruchomiona w tym wątku. Każdy nieprzechwycony wyjątek spowoduje przerwanie transakcji i wyjście z dosync.
Poniżej znajduje się składnia.
Składnia
(dosync expression)
Parameters - „wyrażenie” to zestaw wyrażeń, które pojawią się w bloku dosync.
Return Value - Żaden.
Spójrzmy na przykład, w którym próbujemy zmienić wartość zmiennej referencyjnej.
Przykład
(ns clojure.examples.example
(:gen-class))
(defn Example []
(def names (ref []))
(alter names conj "Mark"))
(Example)
Wynik
Powyższy program po uruchomieniu daje następujący błąd.
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
Z błędu widać wyraźnie, że nie można zmienić wartości typu referencyjnego bez uprzedniego zainicjowania transakcji.
Aby powyższy kod działał, musimy umieścić polecenie alter w bloku dosync, tak jak to zrobiono w poniższym programie.
Przykład
(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)
Powyższy program generuje następujące dane wyjściowe.
Wynik
[John Mark]
Zobaczmy kolejny przykład dosync.
Przykład
(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)
W powyższym przykładzie mamy dwie wartości, które są zmieniane w bloku dosync. Jeśli transakcja się powiedzie, obie wartości zmienią się, w przeciwnym razie cała transakcja zakończy się niepowodzeniem.
Powyższy program generuje następujące dane wyjściowe.
Wynik
10 20
-10 40
Clojure ma kilka współtworzonych bibliotek, które mają możliwość tworzenia Desktop i Web-based applications. Omówmy każdy z nich.
Sr.No. | Aplikacje i opis |
---|---|
1 | Pulpit - See-saw See-saw to biblioteka, której można używać do tworzenia aplikacji desktopowych. |
2 | Pulpit - zmiana wartości tekstu Wartość zawartości w oknie można zmienić za pomocą ‘config!’opcja. W poniższym przykładzie plik config! Opcja służy do zmiany zawartości okna na nową wartość „Good Bye”. |
3 | Pulpit - wyświetlanie modalnego okna dialogowego Modalne okno dialogowe można wyświetlić za pomocą metody alertu klasy see-saw. Metoda przyjmuje wartość tekstową, która musi być pokazana w modalnym oknie dialogowym. |
4 | Pulpit - wyświetlanie przycisków Przyciski można wyświetlać za pomocą klasy przycisków. |
5 | Komputer stacjonarny - wyświetlanie etykiet Etykiety można wyświetlać za pomocą klasy etykiety. |
6 | Pulpit - wyświetlanie pól tekstowych Pola tekstowe można wyświetlać za pomocą klasy tekstowej. |
Aplikacje internetowe - wprowadzenie
Aby stworzyć aplikację internetową w Clojure, musisz skorzystać z biblioteki aplikacji Ring, która jest dostępna pod poniższym linkiem https://github.com/ring-clojure/ring
Musisz upewnić się, że pobierasz niezbędne pliki jar z witryny i dodasz je jako zależność dla aplikacji Clojure.
Plik Ring framework zapewnia następujące możliwości -
Ustawia rzeczy w taki sposób, że żądanie http przychodzi do Twojej aplikacji internetowej jako zwykła Clojure HashMap i podobnie sprawia, że możesz zwrócić odpowiedź jako HashMap.
Zawiera specyfikację opisującą dokładnie, jak powinny wyglądać te mapy żądań i odpowiedzi.
Przenosi serwer WWW (Jetty) i łączy z nim twoją aplikację internetową.
Struktura Ring automatycznie może uruchomić serwer WWW i zapewnia, że aplikacja Clojure działa na tym serwerze. Wtedy można też skorzystać z frameworka Compojure. Pozwala to na tworzenie tras, tak jak obecnie opracowuje się większość nowoczesnych aplikacji internetowych.
Creating your first Clojure application - Poniższy przykład pokazuje, jak utworzyć pierwszą aplikację internetową w 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))
Spójrzmy na następujące aspekty programu -
Plik ‘defroutes’ służy do tworzenia tras, dzięki czemu żądania skierowane do aplikacji sieci Web dotyczące różnych tras mogą być kierowane do różnych funkcji w aplikacji Clojure.
W powyższym przykładzie znak „/” jest znany jako trasa domyślna, więc gdy przejdziesz do bazy aplikacji internetowej, do przeglądarki zostanie wysłany ciąg „Hello World”.
Jeśli użytkownik trafi na dowolny adres URL, którego aplikacja Clojure nie może przetworzyć, wyświetli komunikat „Nie znaleziono”.
Po uruchomieniu aplikacji Clojure aplikacja zostanie domyślnie załadowana jako localhost: 3000, więc jeśli przejdziesz do tej lokalizacji, otrzymasz następujące dane wyjściowe.
Aplikacje internetowe - dodawanie większej liczby tras do aplikacji sieci Web
Możesz także dodać więcej tras do swojej aplikacji internetowej. Poniższy przykład pokazuje, jak to osiągnąć.
(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))
Widać, że dodanie trasy w aplikacji jest tak proste, jak dodanie kolejnej funkcji GET z trasą adresu URL. (GET "/ Tutorial" [] "To jest samouczek dotyczący Clojure")
Jeśli przejdziesz do lokalizacji http://localhost:3000/Tutorial, otrzymasz następujący wynik.
W tym rozdziale omówimy opcje automatycznego testowania zapewniane przez Clojure.
Testowanie aplikacji klienckich
Aby użyć testowania dla frameworka Clojure, musisz użyć zależności znajdujących się pod adresem https://github.com/slagyr/speclj#manual-installation
Ten adres URL zawiera specljFramework, który jest używany jako platforma testowa oparta na danych testowych lub oparta na zachowaniu dla Clojure. Musisz się upewnić, że używasz frameworka Clojure 1.7.0 podczas korzystania z którejkolwiek z bibliotek „speclj”. Domyślnie pliki testowe będą się różnić od plików kodu Clojure i należy je umieścić w katalogu „spec”.
Poniżej znajduje się przykładowy kod pliku testowego.
(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)
Należy zwrócić uwagę na następujące rzeczy dotyczące powyższego kodu -
Najpierw musimy upewnić się, że używamy instrukcji „require”, aby uwzględnić wszystkie podstawowe biblioteki we frameworku „speclj”.
Dalej jest funkcja „opisz”. Służy do zapewnienia opisu tworzonego przypadku testowego.
Następną funkcją jest funkcja „it”, która jest rzeczywistym przypadkiem testowym. W pierwszym przypadku testowym ciąg „jest prawdą” to nazwa nadana przypadkowi testowemu.
Powinien i nie powinien być znany jako assertions. Wszystkie twierdzenia zaczynają się od słów „powinny”. Powinien i nie powinien, to tylko dwa z wielu dostępnych twierdzeń. Obaj przyjmują wyrażenia, które sprawdzą odpowiednio pod kątem prawdziwości i fałszu.
Jeśli uruchomisz przypadek testowy, otrzymasz następujące dane wyjściowe. Dane wyjściowe pokazują czas w milisekundach potrzebny do uruchomienia przypadku testowego.
←[32m.←[0m←[32m.←[0m
Finished in 0.00014 seconds
Testowanie aplikacji internetowych
Seleniumjest jednym z kluczowych frameworków używanych do testowania współczesnych aplikacji internetowych. Dostępne są również biblioteki Clojure, których można używać do testowania aplikacji internetowych.
Przyjrzyjmy się, jak możemy wykorzystać biblioteki Selenium do testowania aplikacji internetowych Clojure.
Step 1- Pierwszym krokiem jest upewnienie się, że używamy frameworka Ring and Compojure do tworzenia aplikacji internetowej, którą należy przetestować. Skorzystajmy z jednego z przykładów z naszych wcześniejszych rozdziałów. Poniższy kod to prosta aplikacja internetowa, która wyświetla „Hello World” w przeglądarce.
(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 - Następnie pobierz plik jar selenu https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server/2.47.0 i dołącz go do swojej ścieżki klas.
Step 3 - Upewnij się również, że pobrałeś sterownik sieciowy „clj”, który będzie używany do uruchamiania testu internetowego z następującej lokalizacji.
https://clojars.org/clj-webdriver/versions/0.7.1
Step 4 - W katalogu projektu utwórz inny katalog o nazwie features i utwórz plik o nazwie „config.clj”.
Step 5 - Następnie dodaj następujący kod do pliku „config.clj” utworzonego we wcześniejszym kroku.
ns clj-webdriver-tutorial.features.config)
(def test-port 3000)
(def test-host "localhost")
(def test-base-url (str "http://" test-host ":" test-port "/"))
Powyższy kod w zasadzie mówi platformie testowej sieci Web, aby przetestowała aplikację, która jest ładowana pod adresem URL http://localhost:3000
Step 6 - Na koniec napiszmy nasz kod, aby przeprowadzić nasz 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)))
Powyższy kod podejmie następujące działania -
- Uruchom serwer aplikacji.
- Otwórz ścieżkę główną w przeglądarce.
- Sprawdź, czy na stronie jest komunikat „Hello World”.
- Zamknij przeglądarkę.
- Zamknij serwer.
Jedną rzeczą, która sprawia, że biblioteka Clojure jest tak potężna, jest liczba bibliotek dostępnych dla frameworka Clojure. Widzieliśmy już tak wiele bibliotek używanych we wcześniejszych przykładach do testowania sieci, tworzenia stron internetowych, tworzenia aplikacji opartych na swing, bibliotekę jdbc do łączenia się z bazami danych MySQL. Poniżej znajduje się tylko kilka przykładów kilku kolejnych bibliotek.
data.xml
Ta biblioteka umożliwia Clojure pracę z danymi XML. Używana wersja biblioteki to org.clojure / data.xml „0.0.8”. Plik data.xml obsługuje analizę i emisję XML. Funkcje analizujące odczytują XML z czytnika lub strumienia danych wejściowych.
Przykład
Poniżej znajduje się przykład przetwarzania danych z ciągu znaków na 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
Ta biblioteka umożliwia Clojure pracę z danymi JSON. Używana wersja biblioteki to org.clojure / data.json "0.2.6".
Przykład
Poniżej znajduje się przykład użycia tej biblioteki.
(ns clojure.examples.example
(:require [clojure.data.json :as json])
(:gen-class))
(defn Example []
(println (json/write-str {:a 1 :b 2})))
(Example)
Wynik
Powyższy program generuje następujące dane wyjściowe.
{\"a\":1,\"b\":2}
data.csv
Ta biblioteka pozwala Clojure na pracę z ‘csv’dane. Używana wersja biblioteki to org.clojure / data.csv „0.1.3”.
Przykład
Poniżej znajduje się przykład użycia tej biblioteki.
(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)
W powyższym kodzie funkcja „csv” najpierw odczyta plik o nazwie in-file.csvi umieść wszystkie dane w zmiennej w pliku. Następnie używamy funkcji write-csv do zapisania wszystkich danych do pliku o nazwieout-file.csv.