Clojure - Hướng dẫn nhanh

Clojure là một ngôn ngữ lập trình hàm động, cấp cao. Clojure được thiết kế dựa trên ngôn ngữ lập trình LISP và có các trình biên dịch giúp nó chạy trên cả môi trường thời gian chạy Java và .Net.

Trước khi nói về Clojure, chúng ta hãy mô tả nhanh về ngôn ngữ lập trình LISP. LISP có lõi ngôn ngữ nhỏ, hầu như không có cú pháp và một phương tiện macro mạnh mẽ. Với những tính năng này, bạn có thể bẻ cong LISP để đáp ứng thiết kế của mình, thay vì ngược lại. LISP đã tồn tại từ rất lâu từ năm 1958.

LISP thông thường đọc trong một biểu thức, đánh giá nó và sau đó in ra kết quả. Ví dụ: nếu bạn muốn tính giá trị của một biểu thức toán học đơn giản là 4 + 6 thì bạn nhập vào.

USER(1) (+ 4 6)

Clojure có các mục tiêu chính cấp cao sau đây như một ngôn ngữ lập trình.

  • Nó dựa trên ngôn ngữ lập trình LISP làm cho các câu lệnh mã của nó nhỏ hơn các ngôn ngữ lập trình truyền thống.

  • Nó là một ngôn ngữ lập trình chức năng.

  • Nó tập trung vào tính bất biến về cơ bản là khái niệm mà bạn không nên thực hiện bất kỳ thay đổi nào đối với các đối tượng được tạo tại chỗ.

  • Nó có thể quản lý trạng thái của một ứng dụng cho lập trình viên.

  • Nó hỗ trợ đồng thời.

  • Nó bao gồm các ngôn ngữ lập trình hiện có. Ví dụ, Clojure có thể sử dụng toàn bộ hệ sinh thái Java để quản lý việc chạy mã thông qua JVM.

Trang web chính thức của Clojure là https://clojure.org/

Có nhiều cách khác nhau để làm việc với Clojure như một ngôn ngữ lập trình. Chúng ta sẽ xem xét hai cách để làm việc với lập trình Clojure.

  • Leiningen - Leiningen là một công cụ thiết yếu để tạo, xây dựng và tự động hóa các dự án Clojure.

  • Eclipse Plugin - Có một plugin tên là CounterClockwise, có sẵn cho Eclipse để thực hiện phát triển Clojure trong IDE Eclipse.

Cài đặt Leiningen

Đảm bảo đáp ứng các yêu cầu Hệ thống sau đây trước khi tiến hành cài đặt.

yêu cầu hệ thống

JDK JDK 1.7 trở lên
Ký ức RAM 2 GB (khuyến nghị)

Step 1- Tải xuống bản cài đặt nhị phân. Đi đến liên kếthttp://leiningen-wininstallerđể tải xuống Windows Installer. Nhấp vào tùy chọn để bắt đầu tải xuống trình cài đặt Groovy.

Step 2 - Khởi chạy Trình cài đặt và nhấp vào nút Tiếp theo.

Step 3 - Chỉ định vị trí cài đặt và nhấp vào nút Tiếp theo.

Step 4- Thiết lập sẽ phát hiện vị trí của cài đặt Java hiện có. Nhấp vào nút Tiếp theo để tiếp tục.

Step 5 - Nhấp vào nút Install để bắt đầu cài đặt.

Sau khi cài đặt xong, nó sẽ cung cấp cho bạn tùy chọn để mở Clojure REPL, đây là một môi trường có thể được sử dụng để tạo và kiểm tra các chương trình Clojure của bạn.

Cài đặt Eclipse

Đảm bảo đáp ứng các yêu cầu Hệ thống sau đây trước khi tiến hành cài đặt.

yêu cầu hệ thống

JDK JDK 1.7 trở lên
Nhật thực Eclipse 4.5 (Sao Hỏa)

Step 1- Mở Eclipse và nhấp vào mục Menu. Nhấp vào Trợ giúp → Thị trường Eclipse.

Step 2- Nhập từ khóa Clojure vào hộp thoại hiện ra và nhấn nút 'Go'. Tùy chọn ngược chiều kim đồng hồ sẽ xuất hiện, nhấp vào nút Cài đặt để bắt đầu cài đặt plugin này.

Step 3 - Trong hộp thoại tiếp theo, nhấp vào nút Xác nhận để bắt đầu cài đặt.

Step 4- Trong hộp thoại tiếp theo, bạn sẽ được yêu cầu chấp nhận thỏa thuận cấp phép. Chấp nhận thỏa thuận cấp phép và nhấp vào nút Kết thúc để tiếp tục cài đặt.

Quá trình cài đặt sẽ bắt đầu và sau khi hoàn tất, nó sẽ nhắc bạn khởi động lại Eclipse.

Sau khi khởi động lại Eclipse, bạn sẽ thấy tùy chọn trong Eclipse để tạo một dự án Clojure mới.

Để hiểu cú pháp cơ bản của Clojure, trước tiên chúng ta hãy xem một chương trình Hello World đơn giản.

Hello World như một chương trình hoàn chỉnh

Viết 'Hello world' trong một chương trình Clojure hoàn chỉnh. Sau đây là một ví dụ.

Thí dụ

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

Những điều sau đây cần được lưu ý về chương trình trên.

  • Chương trình sẽ được viết trong một tệp có tên là main.clj. Phần mở rộng 'clj' là tên phần mở rộng của tệp mã clojure. Trong ví dụ trên, tên của tệp được gọi là main.clj.

  • Từ khóa 'defn' được sử dụng để xác định một hàm. Chúng ta sẽ xem các chức năng chi tiết trong chương khác. Nhưng hiện tại, hãy biết rằng chúng ta đang tạo một hàm có tên là helloworld, hàm này sẽ có mã Clojure chính của chúng ta.

  • Trong mã Clojure của chúng tôi, chúng tôi đang sử dụng câu lệnh 'println' để in “Hello World” ra đầu ra của bảng điều khiển.

  • Sau đó, chúng tôi gọi hàm hello-world để lần lượt chạy câu lệnh 'println'.

Chương trình trên tạo ra kết quả sau.

Đầu ra

Hello World

Hình thức chung của một tuyên bố

Dạng tổng quát của bất kỳ câu lệnh nào cần được đánh giá trong dấu ngoặc nhọn như trong ví dụ sau.

(+ 1 2)

Trong ví dụ trên, toàn bộ biểu thức được đặt trong dấu ngoặc nhọn. Đầu ra của câu lệnh trên là 3. Toán tử + hoạt động giống như một hàm trong Clojure, được sử dụng để cộng các chữ số. Giá trị của 1 và 2 được gọi là parameters to the function.

Chúng ta hãy xem xét một ví dụ khác. Trong ví dụ này, 'str' là toán tử được sử dụng để nối hai chuỗi. Các chuỗi “Hello” và “World” được sử dụng làm tham số.

(str "Hello" "World")

Thí dụ

Nếu chúng ta kết hợp hai câu lệnh trên và viết một chương trình, nó sẽ giống như sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

Hello World
3

Không gian tên

Không gian tên được sử dụng để xác định ranh giới logic giữa các mô-đun được xác định trong Clojure.

Không gian tên hiện tại

Điều này xác định không gian tên hiện tại chứa mã Clojure hiện tại.

Cú pháp

*ns*

Thí dụ

Trong cửa sổ lệnh REPL, hãy chạy lệnh sau.

*ns*

Đầu ra

Khi chúng ta chạy lệnh trên, đầu ra sẽ trì hoãn tùy thuộc vào không gian tên hiện tại là gì. Sau đây là một ví dụ về đầu ra. Không gian tên của mã Clojure là -

clojure.examples.hello

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

Yêu cầu Tuyên bố trong Clojure

Mã Clojure được đóng gói trong các thư viện. Mỗi thư viện Clojure thuộc về một không gian tên, tương tự như một gói Java. Bạn có thể tải thư viện Clojure với câu lệnh 'Yêu cầu'.

Cú pháp

(require quoted-namespace-symbol)

Thí dụ

Sau đây là một ví dụ về cách sử dụng câu lệnh này.

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

Trong đoạn mã trên, chúng tôi đang sử dụng từ khóa 'request' để nhập không gian tên clojure.java.io có tất cả các chức năng cần thiết cho chức năng nhập / xuất. Vì chúng tôi không có thư viện bắt buộc, chúng tôi có thể sử dụng hàm 'tệp' trong đoạn mã trên.

Nhận xét trong Clojure

Nhận xét được sử dụng để ghi lại mã của bạn. Nhận xét dòng đơn được xác định bằng cách sử dụng dấu ;; ở bất kỳ vị trí nào trong dòng. Sau đây là một ví dụ.

Thí dụ

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

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

Dấu phân cách

Trong Clojure, các câu lệnh có thể được tách hoặc phân tách bằng cách sử dụng dấu ngoặc nhọn cong hoặc vuông.

Thí dụ

Sau đây là hai ví dụ.

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

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

6

Thí dụ

Sau đây là một ví dụ khác.

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

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

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

Khoảng trắng

Khoảng trắng có thể được sử dụng trong Clojure để phân chia các thành phần khác nhau của một câu lệnh để rõ ràng hơn. Điều này có thể được thực hiện với sự hỗ trợ của toán tử dấu phẩy (,).

Ví dụ, hai câu lệnh sau là tương đương và đầu ra của cả hai câu lệnh sẽ là 15.

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

Mặc dù Clojure bỏ qua dấu phẩy, đôi khi nó sử dụng chúng để giúp lập trình viên đọc mọi thứ dễ dàng hơn.

Ví dụ: nếu bạn có một bản đồ băm như sau (def a-map {: a 1: b 2: c 3}) và yêu cầu giá trị của nó trong cửa sổ REPL, Clojure sẽ in đầu ra là {: a 1, : b 2,: c 3}.

Kết quả dễ đọc hơn, đặc biệt nếu bạn đang xem một lượng lớn dữ liệu.

Ký hiệu

Trong Clojure, các ký hiệu tương đương với các mã định danh trong các ngôn ngữ lập trình khác. Nhưng không giống như các ngôn ngữ lập trình khác, trình biên dịch coi các ký hiệu là các giá trị chuỗi thực tế. Vì một biểu tượng là một giá trị, một biểu tượng có thể được lưu trữ trong một bộ sưu tập, được truyền như một đối số cho một hàm, v.v., giống như bất kỳ đối tượng nào khác.

Một biểu tượng chỉ có thể chứa các ký tự chữ và số và '* +! /. : - _? ' nhưng không được bắt đầu bằng chữ số hoặc dấu hai chấm.

Sau đây là các ví dụ hợp lệ về các ký hiệu.

tutorial-point!
TUTORIAL
+tutorial+

Cấu trúc dự án Clojure

Cuối cùng, hãy nói về một cấu trúc dự án điển hình cho một dự án Clojure. Vì mã Clojure chạy trên máy ảo Java nên hầu hết cấu trúc dự án trong Clojure tương tự như những gì bạn sẽ tìm thấy trong một dự án java. Sau đây là ảnh chụp nhanh cấu trúc dự án mẫu trong Eclipse cho một dự án Clojure.

Những điều chính sau đây cần được lưu ý về cấu trúc chương trình trên.

  • demo_1 - Đây là gói chứa tệp mã Clojure.

  • core.clj - Đây là tệp mã Clojure chính, sẽ chứa mã cho ứng dụng Clojure.

  • Thư mục Leiningen chứa các tệp như clojure-1.6.0.jar được yêu cầu để chạy bất kỳ ứng dụng dựa trên Clojure nào.

  • Tệp pom.properties sẽ chứa các thông tin như groupId, tạo tác và phiên bản của dự án Clojure.

  • Tệp project.clj chứa thông tin về chính ứng dụng Clojure. Sau đây là mẫu nội dung tệp dự án.

(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) là một công cụ để thử nghiệm với mã Clojure. Nó cho phép bạn tương tác với một chương trình đang chạy và nhanh chóng thử xem mọi thứ có diễn ra như bình thường không. Nó thực hiện điều này bằng cách hiển thị cho bạn lời nhắc để bạn có thể nhập mã. Sau đó, nó sẽ đọc đầu vào của bạn, đánh giá nó, in kết quả và lặp lại, hiển thị lại cho bạn lời nhắc.

Quá trình này cho phép một chu kỳ phản hồi nhanh chóng mà hầu hết các ngôn ngữ khác không thể thực hiện được.

Bắt đầu phiên REPL

Một phiên REPL có thể được bắt đầu trong Leiningen bằng cách gõ lệnh sau vào dòng lệnh.

lein repl

Điều này sẽ bắt đầu cửa sổ REPL sau.

Sau đó, bạn bắt đầu đánh giá các lệnh Clojure trong cửa sổ REPL theo yêu cầu.

Để bắt đầu phiên REPL trong Eclipse, hãy nhấp vào tùy chọn Menu, đi tới Chạy dưới dạng → Ứng dụng Clojure.

Thao tác này sẽ bắt đầu một phiên REPL mới trong một cửa sổ riêng cùng với đầu ra bảng điều khiển.

Về mặt khái niệm, REPL tương tự như Secure Shell (SSH). Giống như cách bạn có thể sử dụng SSH để tương tác với máy chủ từ xa, Clojure REPL cho phép bạn tương tác với một quy trình Clojure đang chạy. Tính năng này có thể rất mạnh mẽ vì bạn thậm chí có thể đính kèm REPL vào ứng dụng sản xuất trực tiếp và sửa đổi chương trình của bạn khi nó chạy.

Các biến đặc biệt trong REPL

REPL bao gồm một số biến hữu ích, biến được sử dụng rộng rãi là biến đặc biệt * 1, * 2 và * 3. Chúng được sử dụng để đánh giá kết quả của ba biểu thức gần đây nhất.

Ví dụ sau cho thấy cách sử dụng các biến này.

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

Trong ví dụ trên, hai chuỗi đầu tiên đang được gửi đến cửa sổ xuất REPL lần lượt là “Xin chào” và “Thế giới”. Sau đó, các biến * 2 và * 1 được sử dụng để gọi lại 2 biểu thức được đánh giá cuối cùng.

Clojure cung cấp nhiều loại built-in data types.

Các loại dữ liệu tích hợp

Sau đây là danh sách các kiểu dữ liệu được định nghĩa trong Clojure.

  • Integers - Sau đây là cách biểu diễn Số nguyên có sẵn trong Clojure.

    • Decimal Integers (Short, Long and Int)- Chúng được sử dụng để biểu diễn các số nguyên. Ví dụ: 1234.

    • Octal Numbers- Chúng được sử dụng để biểu diễn số trong biểu diễn bát phân. Ví dụ: 012.

    • Hexadecimal Numbers- Chúng được sử dụng để biểu diễn số trong biểu diễn. Ví dụ: 0xff.

    • Radix Numbers- Chúng được sử dụng để biểu diễn số trong biểu diễn cơ số. Ví dụ: 2r1111 trong đó cơ số là một số nguyên từ 2 đến 36, bao gồm cả.

  • Floating point

    • Giá trị mặc định được sử dụng để biểu diễn số dấu phẩy động 32 bit. Ví dụ, 12,34.

    • Biểu diễn khác là ký hiệu khoa học. Ví dụ: 1.35e-12.

  • char- Điều này xác định một ký tự đơn lẻ. Các ký tự được xác định bằng biểu tượng phản ứng dữ dội. Ví dụ, / e.

  • Boolean - Giá trị này đại diện cho một giá trị Boolean, có thể đúng hoặc sai.

  • String- Đây là các ký tự văn bản được biểu diễn dưới dạng chuỗi ký tự. Ví dụ: “Hello World”.

  • Nil - Điều này được sử dụng để đại diện cho một giá trị NULL trong Clojure.

  • Atom- Nguyên tử cung cấp cách quản lý trạng thái dùng chung, đồng bộ, độc lập. Chúng là một loại tham chiếu như refs và vars.

Giá trị ràng buộc

Vì tất cả các kiểu dữ liệu trong Clojure đều được kế thừa từ Java, nên các giá trị bị ràng buộc giống như trong ngôn ngữ lập trình Java. Bảng sau đây cho thấy các giá trị tối đa được phép cho các chữ số và chữ số thập phân.

chữ Các dãy
Ngắn -32,768 đến 32,767
int -2.147.483.648 đến 2.147.483.647
Dài -9,223,372,036,854,775,808 đến +9,223,372,036,854,775,807
Phao nổi 1,40129846432481707e-45 đến 3,40282346638528860e + 38
gấp đôi 4.94065645841246544e-324ngày đến 1.79769313486231570e + 308ngày

Loại số lớp

Ngoài các kiểu nguyên thủy, các kiểu đối tượng sau đây (đôi khi được gọi là kiểu trình bao bọc) được phép.

Tên
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double

Thí dụ

Chương trình sau đây hiển thị một mã clojure hợp nhất để chứng minh các kiểu dữ liệu trong 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)

Đầu ra

Chương trình trên tạo ra kết quả sau.

1
1.25
Hello

Trong Clojure, variables được xác định bởi ‘def’từ khóa. Nó hơi khác một chút trong đó khái niệm về các biến có liên quan nhiều hơn đến ràng buộc. Trong Clojure, một giá trị được liên kết với một biến. Một điều quan trọng cần lưu ý trong Clojure là các biến là bất biến, có nghĩa là để giá trị của biến thay đổi, nó cần phải bị hủy và tạo lại một lần nữa.

Sau đây là các loại biến cơ bản trong Clojure.

  • short- Điều này được sử dụng để biểu diễn một số ngắn. Ví dụ, 10.

  • int- Điều này được sử dụng để biểu diễn các số nguyên. Ví dụ: 1234.

  • long- Điều này được sử dụng để biểu thị một số dài. Ví dụ: 10000090.

  • float- Điều này được sử dụng để biểu diễn số dấu phẩy động 32-bit. Ví dụ, 12,34.

  • char- Điều này xác định một ký tự đơn lẻ. Ví dụ: '/ a'.

  • Boolean - Giá trị này đại diện cho một giá trị Boolean, có thể đúng hoặc sai.

  • String- Đây là các ký tự văn bản được biểu diễn dưới dạng chuỗi ký tự. Ví dụ: “Hello World”.

Khai báo biến

Sau đây là cú pháp chung của việc xác định một biến.

Cú pháp

(def var-name var-value)

Trong đó 'var-name' là tên của biến và 'var-value' là giá trị liên kết với biến.

Thí dụ

Sau đây là một ví dụ về khai báo biến.

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

Đặt tên biến

Tên của một biến có thể bao gồm các chữ cái, chữ số và ký tự gạch dưới. Nó phải bắt đầu bằng một chữ cái hoặc một dấu gạch dưới. Chữ hoa và chữ thường khác nhau vì Clojure, giống như Java là một ngôn ngữ lập trình phân biệt chữ hoa chữ thường.

Thí dụ

Sau đây là một số ví dụ về đặt tên biến trong 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 - Trong các câu trên, vì phân biệt chữ hoa chữ thường, status và STATUS là hai biến khác nhau được định nghĩa trong Clojure.

Ví dụ trên cho thấy cách xác định một biến có ký tự gạch dưới.

Các biến in

Vì Clojure sử dụng môi trường JVM nên bạn cũng có thể sử dụng hàm 'println'. Ví dụ sau đây cho thấy điều này có thể đạt được như thế nào.

Thí dụ

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

1
1.25
Hello

An operator là một ký hiệu thông báo cho trình biên dịch thực hiện các thao tác toán học hoặc logic cụ thể.

Clojure có các loại toán tử sau:

  • Toán tử số học
  • Toán tử quan hệ
  • Toán tử logic
  • Toán tử bitwise

Note - Trong Clojure, các toán tử và toán hạng hoạt động theo cách thức cú pháp sau.

Cú pháp

(operator operand1 operand2 operandn)

Ví dụ,

Thí dụ

(+ 1 2)

Ví dụ trên thực hiện một phép toán số học trên các số 1 và 2.

Toán tử số học

Ngôn ngữ Clojure hỗ trợ các toán tử Số học bình thường như bất kỳ ngôn ngữ nào. Sau đây là các toán tử Số học có sẵn trong Clojure.

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
+ Phép cộng hai toán hạng (+ 1 2) sẽ cho 3
- Trừ toán hạng thứ hai với toán hạng đầu tiên (- 2 1) sẽ cho 1
* Phép nhân của cả hai toán hạng (* 2 2) sẽ cho 4
/ Chia tử số cho mẫu số (float (/ 3 2)) sẽ cho 1,5
inc Toán tử tăng dần được sử dụng để tăng giá trị của một toán hạng lên 1 inc 5 sẽ cho 6
tháng mười hai Toán tử tăng dần được sử dụng để giảm giá trị của một toán hạng đi 1 ngày 5 tháng mười hai sẽ cho 4
tối đa Trả về đối số lớn nhất của nó tối đa 1 2 3 sẽ trả về 3
min Trả về giá trị nhỏ nhất trong số các đối số của nó tối thiểu 1 2 3 sẽ trả về 1
rem Phần dư của số thứ nhất chia cho số thứ hai rem 3 2 sẽ cho 1

Toán tử quan hệ

Toán tử quan hệ cho phép so sánh các đối tượng. Sau đây là các toán tử quan hệ có sẵn trong Clojure.

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
= Kiểm tra sự bằng nhau giữa hai đối tượng (= 2 2) sẽ cho đúng
không = Kiểm tra sự khác biệt giữa hai đối tượng (not = 3 2) sẽ cho đúng
< Kiểm tra xem đối tượng bên trái có nhỏ hơn toán hạng bên phải không (<2 3) sẽ cho đúng
<= Kiểm tra xem đối tượng bên trái nhỏ hơn hoặc bằng toán hạng bên phải (<= 2 3) sẽ cho đúng
> Kiểm tra xem đối tượng bên trái có lớn hơn toán hạng bên phải không (> 3 2) sẽ cho đúng
> = Kiểm tra xem đối tượng bên trái lớn hơn hoặc bằng toán hạng bên phải (> = 3 2) sẽ cho đúng

Toán tử logic

Các toán tử logic được sử dụng để đánh giá các biểu thức Boolean. Sau đây là các toán tử logic có sẵn trong Groovy.

Hiển thị các ví dụ

Nhà điều hành Sự miêu tả Thí dụ
and Đây là toán tử logic "và" (hoặc đúng true) sẽ cho đúng
or Đây là toán tử logic "hoặc" (và true false) sẽ cho sai
not Đây là toán tử logic "không phải" (không sai) sẽ cho đúng

Đoạn mã sau đây cho thấy cách sử dụng các toán tử khác nhau.

Toán tử Bitwise

Clojure cung cấp bốn toán tử bitwise. Sau đây là các toán tử bitwise có sẵn trong Clojure.

Hiển thị các ví dụ

Sr.No. Nhà điều hành & Mô tả
1

bit-and

Đây là toán tử "và" theo bitwise

2

bit-or

Đây là toán tử "hoặc" theo bitwise

3

bit-xor

Đây là toán tử bitwise "xor" hoặc Exclusive 'hoặc'

4

bit-not

Đây là toán tử phủ định theo bit

Sau đây là bảng sự thật hiển thị các toán tử này.

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

ưu tiên điều hành

Như trường hợp của LISP nói chung, không cần phải lo lắng về mức độ ưu tiên của người vận hành. Đây là một trong những lợi ích của S-Expressions và ký hiệu tiền tố. Tất cả các chức năng đánh giá từ trái sang phải và từ trong ra ngoài. Các toán tử trong Clojure chỉ là các hàm và mọi thứ đều được đặt trong ngoặc đơn.

Cho đến nay chúng ta đã thấy các câu lệnh được thực hiện lần lượt theo cách tuần tự. Ngoài ra, các câu lệnh được cung cấp trong Clojure để thay đổi luồng điều khiển trong logic của chương trình. Sau đó, chúng được phân loại thành luồng báo cáo kiểm soát mà chúng ta sẽ xem chi tiết.

Sr.No. Vòng lặp & Mô tả
1 Tuyên bố While

Các 'while' câu lệnh được thực hiện bằng cách đánh giá trước biểu thức điều kiện (một giá trị Boolean), và nếu kết quả là true thì các câu lệnh trong vòng lặp while sẽ được thực thi.

2 Tuyên bố Doseq

Các ‘doseq’câu lệnh tương tự như câu lệnh 'for each' được tìm thấy trong nhiều ngôn ngữ lập trình khác. Về cơ bản, câu lệnh liều lượng được sử dụng để lặp lại một chuỗi.

3 Tuyên bố Dotimes

Các ‘dotimes’ câu lệnh được sử dụng để thực hiện một câu lệnh 'x' số lần.

4 Tuyên bố vòng lặp

Dạng đặc biệt của vòng lặp không giống như một ‘for’vòng. Việc sử dụng vòng lặp cũng giống như ràng buộc let. Tuy nhiên, vòng lặp đặt một điểm đệ quy

Decision-making structures yêu cầu người lập trình chỉ định một hoặc nhiều điều kiện để được đánh giá hoặc kiểm tra bởi chương trình, cùng với một câu lệnh hoặc các câu lệnh được thực thi nếu điều kiện được xác định là đúng, và tùy chọn, các câu lệnh khác sẽ được thực hiện nếu điều kiện được xác định là sai.

Sr.No. Phương pháp & Mô tả
1 Nếu tuyên bố

Trong Clojure, điều kiện là một biểu thức đánh giá nó là đúng hoặc sai. 'If' điều kiện là đúng thì câu lệnh số 1 sẽ được thực hiện, câu lệnh khác số 2 sẽ được thực hiện.

2 If / do Expression

Các ‘if-do’ biểu thức trong Clojure được sử dụng để cho phép nhiều biểu thức được thực thi cho mỗi nhánh của câu lệnh 'if'.

3 Câu lệnh If lồng nhau

Nhiều 'if' các câu lệnh được nhúng bên trong nhau.

4 Báo cáo tình huống

Clojure cung cấp ‘case’ câu lệnh tương tự như câu lệnh ‘switch’ câu lệnh có sẵn bằng ngôn ngữ lập trình Java.

5 Báo cáo điều kiện

Clojure đưa ra một tuyên bố đánh giá khác được gọi là ‘cond’tuyên bố. Câu lệnh này nhận một tập hợp các cặp kiểm tra / biểu thức.

Clojure được biết đến như một ngôn ngữ lập trình chức năng, do đó bạn sẽ mong đợi thấy nhiều sự nhấn mạnh về cách các chức năng hoạt động trong Clojure. Chương này bao gồm tất cả những gì có thể được thực hiện với các chức năng trong Clojure.

Sr.No. Chức năng & Mô tả
1 Xác định một chức năng

Một hàm được xác định bằng cách sử dụng ‘defn’ vĩ mô.

2 Chức năng ẩn danh

Một hàm ẩn danh là một hàm không có tên liên quan đến nó.

3 Các hàm với nhiều đối số

Các hàm Clojure có thể được xác định với không hoặc nhiều tham số. Các giá trị bạn chuyển cho các hàm được gọi làarguments, và các đối số có thể thuộc bất kỳ loại nào.

4 Chức năng đa dạng

Clojure đưa ra câu lệnh 'case' tương tự như câu lệnh 'switch' có sẵn trong ngôn ngữ lập trình Java.

5 Chức năng đặt hàng cao hơn

Các hàm bậc cao hơn (HOF) là các hàm lấy các hàm khác làm đối số. HOF là một kỹ thuật lập trình chức năng quan trọng và được sử dụng khá phổ biến trong Clojure.

Numbers datatype trong Clojure có nguồn gốc từ các lớp Java.

Clojure hỗ trợ số nguyên và dấu phẩy động.

  • Một số nguyên là một giá trị không bao gồm một phân số.

  • Số dấu phẩy động là một giá trị thập phân bao gồm một phân số thập phân.

Sau đây là một ví dụ về các con số trong Clojure.

(def x 5)
(def y 5.25)

Trong đó 'x' thuộc loại Integer và 'y' là float.

Trong Java, các lớp sau được gắn với các số được định nghĩa trong Clojure.

Để thực sự thấy rằng các số trong Clojure có nguồn gốc từ các lớp Java, hãy sử dụng chương trình sau để xem loại số được gán khi sử dụng lệnh 'def'.

Thí dụ

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

Các ‘type’ lệnh được sử dụng để xuất ra lớp được liên kết với giá trị được gán cho một biến.

Đầu ra

Đoạn mã trên sẽ tạo ra kết quả sau.

Java.lang.long
Java.lang.double

Kiểm tra số

Các chức năng kiểm tra sau đây có sẵn cho các số.

Sr.No. Số & Mô tả
1 số không?

Trả về true nếu số bằng 0, ngược lại là false.

2 vị trí?

Trả về true nếu số lớn hơn 0, ngược lại là false.

3 phủ định?

Trả về true nếu số nhỏ hơn 0, ngược lại là false.

4 cũng?

Trả về true nếu số là số chẵn và ném ngoại lệ nếu số đó không phải là số nguyên.

5 kỳ quặc?

Trả về true nếu số là số lẻ và ném ngoại lệ nếu số đó không phải là số nguyên.

6 con số?

Trả về true nếu số thực sự là Số.

7 số nguyên?

Trả về true nếu số là số nguyên.

số 8 Phao nổi?

Trả về true nếu số là số thực.

Chúng ta đã thấy câu lệnh lặp lại trong một chủ đề trước đó và trong khi vòng lặp 'for' giống như một vòng lặp, recur là một vòng lặp thực sự trong Clojure.

Nếu bạn có kiến ​​thức nền tảng về lập trình, bạn có thể đã nghe nói về đệ quy đuôi, đây là một tính năng chính của các ngôn ngữ hàm. Dạng đặc biệt định kỳ này là dạng thực hiện đệ quy đuôi. Như từ “đệ quy đuôi” chỉ ra, định kỳ phải được gọi ở vị trí đuôi. Nói cách khác, định kỳ phải là điều cuối cùng được đánh giá.

Ví dụ đơn giản nhất về câu lệnh lặp được sử dụng trong vòng lặp 'for'. Trong ví dụ sau, câu lệnh lặp được sử dụng để thay đổi giá trị của biến 'i' và cung cấp giá trị của biến trở lại biểu thức vòng lặp.

Thí dụ

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

0
1
2
3
4

Clojure cung cấp một số phương thức trợ giúp khi làm việc với I / O. Nó cung cấp các lớp dễ dàng hơn để cung cấp các chức năng sau cho tệp.

  • Đọc tệp
  • Ghi vào tệp
  • Xem tệp là tệp hay thư mục

Hãy cùng khám phá một số thao tác tệp mà Clojure cung cấp.

Đọc nội dung của tệp dưới dạng toàn bộ chuỗi

Nếu bạn muốn nhận toàn bộ nội dung của tệp dưới dạng chuỗi, bạn có thể sử dụng clojure.core.slurpphương pháp. Lệnh slurp mở một trình đọc trên một tệp và đọc tất cả nội dung của nó, trả về một chuỗi.

Sau đây là một ví dụ về cách điều này có thể được thực hiện.

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

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

Nếu tệp chứa các dòng sau, chúng sẽ được in dưới dạng:

line : Example1
line : Example2

Đọc nội dung của tệp một dòng tại một thời điểm

Nếu bạn muốn nhận toàn bộ nội dung của tệp dưới dạng chuỗi một dòng tại một thời điểm, bạn có thể sử dụng clojure.java.io/readerphương pháp. Lớp clojure.java.io/reader tạo bộ đệm trình đọc, được sử dụng để đọc từng dòng của tệp.

Sau đây là một ví dụ cho thấy cách này có thể được thực hiện.

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

Nếu tệp chứa các dòng sau, chúng sẽ được in dưới dạng:

line : Example1
line : Example2

Đầu ra sẽ được hiển thị là -

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

Ghi 'vào' Tệp

Nếu bạn muốn ghi tệp 'vào', bạn có thể sử dụng clojure.core.spitlệnh để phun toàn bộ chuỗi vào tệp. Lệnh nhổ là ngược lại với phương pháp slurp. Phương pháp này mở một tệp với tư cách người viết, ghi nội dung, sau đó đóng tệp.

Sau đây là một ví dụ.

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

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

Trong ví dụ trên, nếu bạn thấy nội dung của tệp example.txt, bạn sẽ thấy nội dung của “Đây là một chuỗi”.

Viết 'thành' tệp một dòng tại một thời điểm

Nếu bạn muốn ghi các tệp 'vào' từng dòng một, bạn có thể sử dụng clojure.java.io.writerlớp học. Lớp clojure.java.io.writer được sử dụng để tạo luồng người viết, trong đó các byte dữ liệu được đưa vào luồng và sau đó vào tệp.

Sau đây là một ví dụ cho thấy cách sử dụng lệnh nhổ.

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

Khi đoạn mã trên được thực thi, dòng “hello world” sẽ xuất hiện trong tệp Example.txt. Tùy chọn append: true là để nối dữ liệu vào tệp. Nếu tùy chọn này không được chỉ định, thì tệp sẽ bị ghi đè bất cứ khi nào dữ liệu được ghi vào tệp.

Kiểm tra để xem nếu tệp tồn tại

Để kiểm tra xem tệp có tồn tại hay không, clojure.java.io.filelớp có thể được sử dụng để kiểm tra sự tồn tại của một tệp. Sau đây là một ví dụ cho thấy cách này có thể được thực hiện.

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

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

Nếu tệp Example.txt tồn tại, kết quả đầu ra sẽ là true.

Đọc từ Bảng điều khiển

Để đọc dữ liệu từ bảng điều khiển, read-linecâu lệnh có thể được sử dụng. Sau đây là một ví dụ cho thấy cách này có thể được sử dụng.

Nếu bạn nhập lệnh (read-line) trong cửa sổ REPL, bạn sẽ có cơ hội nhập một số đầu vào trong cửa sổ bảng điều khiển.

user->(read-line)
Hello World

Đoạn mã trên sẽ tạo ra kết quả sau.

“Hello World”

A Stringnghĩa đen được xây dựng trong Clojure bằng cách đưa văn bản chuỗi vào dấu ngoặc kép. Các chuỗi trong Clojure cần được xây dựng bằng cách sử dụng dấu ngoặc kép, chẳng hạn như “Hello World”.

Thí dụ

Sau đây là một ví dụ về việc sử dụng các chuỗi trong Clojure.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

Hello World
This is a demo application

Hoạt động chuỗi cơ bản

Clojure có một số hoạt động có thể được thực hiện trên chuỗi. Sau đây là các hoạt động.

Sr.No. Hoạt động và mô tả chuỗi
1 str

Việc nối các chuỗi có thể được thực hiện bằng hàm str đơn giản.

2 định dạng

Việc định dạng chuỗi có thể được thực hiện bằng chức năng định dạng đơn giản. Hàm định dạng định dạng một chuỗi bằng cách sử dụngjava.lang.String.format.

3 đếm

Trả về số ký tự trong chuỗi.

4 người đăng ký

Trả về chuỗi con của 's' bắt đầu từ đầu bao gồm và kết thúc ở cuối (mặc định là độ dài của chuỗi), không bao gồm.

5 so sánh

Trả về số âm, số 0 hoặc số dương khi 'x' về mặt logic là 'nhỏ hơn', 'bằng' hoặc 'lớn hơn' 'y'.

6 chữ thường

Chuyển đổi chuỗi thành tất cả các chữ thường.

7 chữ hoa

Chuyển đổi chuỗi thành tất cả chữ hoa.

số 8 tham gia

Trả về một chuỗi của tất cả các phần tử trong tập hợp, được trả về bởi (tập hợp seq), được phân tách bằng dấu phân tách tùy chọn.

9 tách ra

Tách chuỗi trên một biểu thức chính quy.

10 đường phân chia

Chuỗi phân tách dựa trên các ký tự thoát \ n hoặc \ r \ n.

11 đảo ngược

Đảo ngược các ký tự trong một chuỗi.

12 thay thế

Thay thế tất cả các trường hợp khớp trong một chuỗi bằng chuỗi thay thế.

13 cắt tỉa

Loại bỏ khoảng trắng từ cả hai đầu của chuỗi.

14 triml

Loại bỏ khoảng trắng từ phía bên trái của chuỗi.

15 người cắt tỉa

Loại bỏ khoảng trắng từ phía bên phải của chuỗi.

Listlà một cấu trúc được sử dụng để lưu trữ một tập hợp các mục dữ liệu. Trong Clojure, Danh sách triển khaiISeqgiao diện. Danh sách được tạo trong Clojure bằng cách sử dụng chức năng danh sách.

Thí dụ

Sau đây là một ví dụ về cách tạo danh sách các số trong Clojure.

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

Đầu ra

Đoạn mã trên tạo ra kết quả sau.

(1 2 3 4)

Sau đây là một ví dụ về tạo danh sách các nhân vật trong Clojure.

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

Đoạn mã trên tạo ra kết quả sau.

(a b c d)

Sau đây là danh sách các phương pháp có sẵn trong Clojure.

Sr.No. Danh sách & Mô tả
1 danh sách*

Tạo một danh sách mới chứa các mục được thêm trước vào phần còn lại, phần cuối cùng sẽ được coi là một chuỗi.

2 Đầu tiên

Hàm này trả về mục đầu tiên trong danh sách.

3 thứ n

Hàm này trả về mục ở vị trí 'thứ n' trong danh sách.

4 khuyết điểm

Trả về một danh sách mới, trong đó một phần tử được thêm vào đầu danh sách.

5 gợi ý

Trả về một danh sách mới, trong đó danh sách nằm ở đầu và các phần tử được thêm vào được đặt ở cuối.

6 nghỉ ngơi

Trả về các mục còn lại trong danh sách sau mục đầu tiên.

Setstrong Clojure là một tập hợp các giá trị duy nhất. Tập hợp được tạo trong Clojure với sự trợ giúp của lệnh set.

Thí dụ

Sau đây là một ví dụ về việc tạo các bộ trong Clojure.

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

Đầu ra

Đoạn mã trên tạo ra kết quả sau.

#{1,2}

Sau đây là các phương pháp có sẵn trong Clojure cho các bộ.

Sr.No. Bộ & Mô tả
1 sắp xếp-đặt

Trả về một tập hợp các phần tử đã được sắp xếp.

2 được

Trả về phần tử ở vị trí chỉ mục.

3 chứa đựng?

Tìm xem tập hợp có chứa một phần tử nhất định hay không.

4 gợi ý

Thêm một phần tử vào tập hợp và trả về tập hợp phần tử mới.

5 disj

Tách một phần tử khỏi tập hợp.

6 liên hiệp

Trả về một tập hợp là sự kết hợp của các tập đầu vào

7 Sự khác biệt

Trả về một tập hợp là tập hợp đầu tiên không có phần tử của các tập hợp còn lại.

số 8 ngã tư

Trả về một tập hợp là giao của các tập hợp đầu vào.

9 tập hợp con?

Set1 có phải là tập hợp con của set2 không?

10 superset?

Set1 có phải là tập siêu của set2 không?

A Vectorlà một tập hợp các giá trị được lập chỉ mục bởi các số nguyên liền kề. Một vector được tạo bằng cách sử dụng phương thức vector trong Clojure.

Thí dụ

Sau đây là một ví dụ về cách tạo một vector trong Clojure.

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

Đầu ra

Đoạn mã trên tạo ra kết quả sau.

[1 2 3]

Sau đây là các phương pháp có sẵn trong Clojure.

Sr.No. Vectơ & Mô tả
1 vector-of

Tạo một vectơ mới có kiểu nguyên thủy duy nhất 't', trong đó 't' là một trong số: int: long: float: double: byte: short: char hoặc: boolean.

2 thứ n

Hàm này trả về mục ở vị trí thứ n trong vectơ.

3 được

Trả về phần tử ở vị trí chỉ mục trong vectơ.

4 gợi ý

Thêm một phần tử vào vectơ và trả về tập hợp các phần tử vectơ mới.

5 bật ra

Đối với danh sách hoặc hàng đợi, trả về danh sách / hàng đợi mới không có mục đầu tiên, đối với vectơ, trả về vectơ mới không có mục cuối cùng.

6 subvec

Trả về một vectơ con từ chỉ mục bắt đầu và kết thúc.

A Maplà một tập hợp ánh xạ các khóa đến các giá trị. Hai loại bản đồ khác nhau được cung cấp - băm và sắp xếp.HashMaps yêu cầu các khóa hỗ trợ chính xác Mã băm và bằng. SortedMaps yêu cầu các khóa triển khai So sánh hoặc một phiên bản của Bộ so sánh.

Một bản đồ có thể được tạo theo hai cách, cách thứ nhất là thông qua phương pháp bản đồ băm.

Tạo - HashMaps

HashMaps có mối quan hệ giá trị khóa điển hình và được tạo bằng cách sử dụng hàm hash-map.

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

Đầu ra

Đoạn mã trên tạo ra kết quả sau.

{z 1, b 2, a 3}

Tạo - Bản đồ đã sắp xếp

SortedMaps có đặc điểm duy nhất là sắp xếp các phần tử của chúng dựa trên phần tử chính. Sau đây là một ví dụ cho thấy cách bản đồ đã sắp xếp có thể được tạo bằng cách sử dụng chức năng bản đồ đã sắp xếp.

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

Đoạn mã trên tạo ra kết quả sau.

{a 3, b 2, z 1}

Từ chương trình trên, bạn có thể thấy rõ rằng các phần tử trong bản đồ được sắp xếp theo giá trị khóa. Sau đây là các phương pháp có sẵn cho bản đồ.

Sr.No. Bản đồ & Mô tả
1 được

Trả về giá trị được ánh xạ tới khóa, không tìm thấy hoặc nil nếu không có khóa.

2 chứa đựng?

Xem liệu bản đồ có chứa khóa bắt buộc hay không.

3 tìm thấy

Trả về mục nhập bản đồ cho khóa.

4 chìa khóa

Trả về danh sách các khóa trong bản đồ.

5 vals

Trả về danh sách các giá trị trong bản đồ.

6 phản đối

Tách mục nhập giá trị quan trọng khỏi bản đồ.

7 hợp nhất

Hợp nhất hai mục nhập bản đồ thành một mục nhập bản đồ duy nhất.

số 8 kết hợp với

Trả về một bản đồ bao gồm phần còn lại của các bản đồ được liên kết với bản đồ đầu tiên.

9 phím chọn

Trả về một bản đồ chỉ chứa các mục nhập trong bản đồ có khóa nằm trong các khóa.

10 đổi tên-khóa

Đổi tên các khóa trong HashMap hiện tại thành các khóa mới được xác định.

11 đảo ngược bản đồ

Đảo ngược bản đồ để các giá trị trở thành khóa và ngược lại.

Namespacestrong Clojure được sử dụng để phân biệt các lớp thành các không gian logic riêng biệt giống như trong Java. Hãy xem xét tuyên bố sau đây.

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

Trong câu lệnh trên, 'clojure.set' là một không gian tên chứa các lớp và phương thức khác nhau được sử dụng trong chương trình. Ví dụ, không gian tên ở trên chứa hàm được gọi là map-invert, được sử dụng để đảo ngược bản đồ các khóa-giá trị. Chúng tôi không thể sử dụng chức năng này trừ khi chúng tôi yêu cầu chương trình của chúng tôi bao gồm không gian tên này một cách rõ ràng.

Hãy xem xét các phương pháp khác nhau có sẵn cho không gian tên.

Sr.No. Phương pháp & Mô tả
1 * ns *

Điều này được sử dụng để xem không gian tên hiện tại của bạn.

2 ns

Điều này được sử dụng để tạo một không gian tên mới và liên kết nó với chương trình đang chạy.

3 bí danh

Thêm bí danh trong không gian tên hiện tại vào một không gian tên khác. Đối số là hai ký hiệu: bí danh được sử dụng và tên ký hiệu của không gian tên đích.

4 all-ns

Trả về danh sách tất cả các vùng tên.

5 find-ns

Tìm và trả về một không gian tên cụ thể.

6 ns-name

Trả về tên của một vùng tên cụ thể.

7 ns-bí danh

Trả về các bí danh được liên kết với bất kỳ không gian tên nào.

số 8 ns-map

Trả về một bản đồ của tất cả các ánh xạ cho không gian tên.

9 bỏ bí danh

Trả về một bản đồ chỉ chứa các mục nhập trong bản đồ có khóa nằm trong các khóa.

Exception handlingđược yêu cầu trong bất kỳ ngôn ngữ lập trình nào để xử lý các lỗi thời gian chạy để có thể duy trì luồng bình thường của ứng dụng. Ngoại lệ thường làm gián đoạn luồng thông thường của ứng dụng, đó là lý do tại sao chúng ta cần sử dụng xử lý ngoại lệ trong ứng dụng của mình.

Ngoại lệ được phân loại rộng rãi thành các loại sau:

  • Checked Exception- Các lớp mở rộng lớp Throwable ngoại trừ RuntimeException và Error được gọi là các ngoại lệ đã kiểm tra. Ví dụ: IOException, SQLException, v.v. Các ngoại lệ đã chọn được kiểm tra tại thời điểm biên dịch.

Hãy xem xét chương trình sau đây thực hiện một thao tác trên tệp có tên là Example.txt. Tuy nhiên, luôn có thể có trường hợp trong đó tệp Example.txt không tồn tại.

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

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

Nếu tệp Example.txt không tồn tại, thì chương trình sẽ tạo ra ngoại lệ sau.

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)

Từ ngoại lệ trên, chúng ta có thể thấy rõ ràng rằng chương trình đã tạo ra một FileNotFoundException.

  • Unchecked Exception- Các lớp mở rộng RuntimeException được gọi là các ngoại lệ không được kiểm tra. Ví dụ, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, v.v. Các ngoại lệ chưa được kiểm tra không được kiểm tra tại thời điểm biên dịch thay vì chúng được kiểm tra trong thời gian chạy.

Một trường hợp cổ điển là ArrayIndexOutOfBoundsException xảy ra khi bạn cố gắng truy cập vào chỉ mục của một mảng lớn hơn độ dài của mảng. Sau đây là một ví dụ điển hình của loại sai lầm này.

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

Khi đoạn mã trên được thực thi, ngoại lệ sau sẽ được đưa ra.

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

lỗi

Lỗi không thể khôi phục được, ví dụ như OutOfMemoryError, VirtualMachineError, AssertionError, v.v. Đây là những lỗi mà chương trình không bao giờ có thể khôi phục và sẽ khiến chương trình bị sập. Bây giờ chúng ta cần một số cơ chế để bắt các ngoại lệ này để chương trình có thể tiếp tục chạy nếu các ngoại lệ này tồn tại.

Sơ đồ sau đây cho thấy cách tổ chức phân cấp các ngoại lệ trong Clojure. Tất cả đều dựa trên hệ thống phân cấp được định nghĩa trong Java.

Bắt ngoại lệ

Cũng giống như các ngôn ngữ lập trình khác, Clojure cung cấp khối 'try-catch' bình thường để bắt các ngoại lệ khi và khi chúng xảy ra.

Sau đây là cú pháp chung của khối try-catch.

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

Tất cả mã của bạn có thể tạo ra một ngoại lệ được đặt trong Protected code block.

bên trong catch block, bạn có thể viết mã tùy chỉnh để xử lý ngoại lệ của mình để ứng dụng có thể khôi phục khỏi ngoại lệ.

Hãy xem ví dụ trước đó của chúng tôi đã tạo ra một ngoại lệ không tìm thấy tệp và xem cách chúng tôi có thể sử dụng khối try catch để bắt ngoại lệ do chương trình nêu ra.

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

Chương trình trên tạo ra kết quả sau.

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

Từ đoạn mã trên, chúng tôi đưa ra mã bị lỗi trong try block. Trong khối bắt, chúng tôi chỉ bắt ngoại lệ của mình và xuất ra một thông báo rằng một ngoại lệ đã xảy ra. Vì vậy, bây giờ chúng ta có một cách có ý nghĩa để nắm bắt ngoại lệ, được tạo ra bởi chương trình.

Nhiều khối bắt

Người ta có thể có nhiều khối bắt để xử lý nhiều loại ngoại lệ. Đối với mỗi khối bắt, tùy thuộc vào loại ngoại lệ được nêu ra, bạn sẽ viết mã để xử lý nó cho phù hợp.

Hãy sửa đổi mã trước đó của chúng tôi để bao gồm hai khối bắt, một khối dành riêng cho tệp của chúng tôi không tìm thấy ngoại lệ và khối còn lại dành cho khối ngoại lệ chung.

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

Chương trình trên tạo ra kết quả sau.

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

Từ kết quả đầu ra ở trên, chúng ta có thể thấy rõ rằng ngoại lệ của chúng ta đã bị chặn bởi khối bắt 'FileNotFoundException' chứ không phải khối chung chung.

Cuối cùng là Chặn

Khối cuối cùng theo sau khối thử hoặc khối bắt. Một khối mã cuối cùng luôn thực thi, bất kể sự xuất hiện của Ngoại lệ.

Sử dụng khối cuối cùng cho phép bạn chạy bất kỳ câu lệnh loại dọn dẹp nào mà bạn muốn thực thi, bất kể điều gì xảy ra trong mã được bảo vệ. Sau đây là cú pháp cho khối này.

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

Hãy sửa đổi đoạn mã trên và thêm khối mã cuối cùng. Sau đây là đoạn mã.

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

Chương trình trên tạo ra kết quả sau.

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

Từ chương trình trên, bạn có thể thấy rằng khối cuối cùng cũng được thực hiện sau khi khối bắt bắt được ngoại lệ bắt buộc.

Vì Clojure bắt nguồn xử lý ngoại lệ của nó từ Java, tương tự như Java, các phương pháp sau có sẵn trong Clojure để quản lý các ngoại lệ.

  • public String getMessage()- Trả về một thông báo chi tiết về ngoại lệ đã xảy ra. Thông báo này được khởi tạo trong phương thức khởi tạo Throwable.

  • public Throwable getCause() - Trả về nguyên nhân của ngoại lệ như được đại diện bởi một đối tượng Throwable.

  • public String toString() - Trả về tên của lớp được ghép với kết quả của getMessage ().

  • public void printStackTrace() - In kết quả của toString () cùng với dấu vết ngăn xếp lên System.err, luồng đầu ra lỗi.

  • public StackTraceElement [] getStackTrace()- Trả về một mảng chứa mỗi phần tử trên dấu vết ngăn xếp. Phần tử ở chỉ số 0 đại diện cho phần trên cùng của ngăn xếp cuộc gọi và phần tử cuối cùng trong mảng đại diện cho phương thức ở cuối ngăn xếp cuộc gọi.

  • public Throwable fillInStackTrace() - Làm đầy dấu vết ngăn xếp của đối tượng Throwable này với dấu vết ngăn xếp hiện tại, thêm vào bất kỳ thông tin nào trước đó trong dấu vết ngăn xếp.

Sau đây là mã ví dụ sử dụng một số phương pháp được liệt kê ở trên.

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

Chương trình trên tạo ra kết quả sau.

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

Sequences được tạo ra với sự trợ giúp của ‘seq’chỉ huy. Sau đây là một ví dụ đơn giản về tạo chuỗi.

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

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

Chương trình trên tạo ra kết quả sau.

(1 2 3)

Sau đây là các phương pháp khác nhau có sẵn cho trình tự.

Sr.No. Phương pháp & Mô tả
1 khuyết điểm

Trả về một chuỗi mới trong đó 'x' là phần tử đầu tiên và 'seq' là phần còn lại.

2 gợi ý

Trả về một chuỗi mới trong đó 'x' là phần tử được thêm vào cuối chuỗi.

3 kết hợp

Điều này được sử dụng để nối hai chuỗi với nhau.

4 khác biệt

Được sử dụng để chỉ đảm bảo rằng các phần tử riêng biệt được thêm vào chuỗi.

5 đảo ngược

Đảo ngược các phần tử trong chuỗi.

6 Đầu tiên

Trả về phần tử đầu tiên của dãy.

7 Cuối cùng

Trả về phần tử cuối cùng của dãy.

số 8 nghỉ ngơi

Trả về toàn bộ chuỗi ngoại trừ phần tử đầu tiên.

9 sắp xếp

Trả về một chuỗi các phần tử đã được sắp xếp.

10 rơi vãi

Loại bỏ các phần tử khỏi một trình tự dựa trên số lượng phần tử cần được loại bỏ.

11 lấy cuối cùng

Lấy danh sách các phần tử cuối cùng từ chuỗi.

12 lấy

Lấy danh sách các phần tử đầu tiên từ chuỗi.

13 tách ra

Tách chuỗi các mục thành hai phần. Một vị trí được chỉ định mà tại đó sự phân tách sẽ xảy ra.

A regular expressionlà một mẫu được sử dụng để tìm các chuỗi con trong văn bản. Biểu thức chính quy được sử dụng trong nhiều ngôn ngữ lập trình và được sử dụng rất nhiều trong các ngôn ngữ lập trình kiểu LISP.

Sau đây là một ví dụ về một biểu thức chính quy.

//d+

Biểu thức chính quy ở trên được sử dụng để tìm thêm một lần xuất hiện của một chữ số trong một chuỗi. Các ký tự // được sử dụng để đảm bảo rằng các ký tự 'd' và '+' được sử dụng để đại diện cho một biểu thức chính quy.

Nói chung, biểu thức chính quy hoạt động với bộ quy tắc sau.

  • Có hai ký tự vị trí đặc biệt được sử dụng để biểu thị đầu và cuối dòng: dấu mũ (∧) và dấu đô la ($):

  • Biểu thức chính quy cũng có thể bao gồm các bộ định lượng. Dấu cộng (+) đại diện cho một hoặc nhiều lần, được áp dụng cho phần tử đứng trước của biểu thức. Dấu hoa thị (*) được sử dụng để thể hiện không hoặc nhiều lần xuất hiện. Dấu chấm hỏi (?) Biểu thị không hoặc một lần.

  • Siêu ký tự {và} được sử dụng để đối sánh với một số trường hợp cụ thể của ký tự đứng trước.

  • Trong biểu thức chính quy, ký hiệu dấu chấm (.) Có thể đại diện cho bất kỳ ký tự nào. Đây được mô tả là ký tự đại diện.

  • Một biểu thức chính quy có thể bao gồm các lớp ký tự. Một tập hợp các ký tự có thể được cung cấp dưới dạng một chuỗi ký tự đơn giản được bao quanh trong siêu ký tự [và] như trong [aeiou]. Đối với phạm vi chữ cái hoặc số, bạn có thể sử dụng dấu gạch ngang như trong [a – z] hoặc [a – mA – M]. Phần bổ sung của một lớp ký tự được biểu thị bằng dấu mũ đứng đầu bên trong dấu ngoặc vuông như trong [∧a – z] và đại diện cho tất cả các ký tự khác với những ký tự được chỉ định.

Các phương thức sau có sẵn cho các biểu thức chính quy.

Sr.No. Phương pháp & Mô tả
1 mô hình lại

Trả về một phiên bản của java.util.regex.Pattern. Điều này sau đó được sử dụng trong các phương pháp khác để đối sánh mẫu.

2 refind

Trả về kết quả khớp regex tiếp theo, nếu có, của chuỗi thành mẫu, sử dụng java.util.regex.Matcher.find ()

3 thay thế

Hàm Replace được sử dụng để thay thế một chuỗi con trong chuỗi bằng một giá trị chuỗi mới. Việc tìm kiếm chuỗi con được thực hiện với việc sử dụng một mẫu.

4 thay thế đầu tiên

Hàm thay thế được sử dụng để thay thế một chuỗi con trong một chuỗi bằng một giá trị chuỗi mới, nhưng chỉ cho lần xuất hiện đầu tiên của chuỗi con. Việc tìm kiếm chuỗi con được thực hiện với việc sử dụng một mẫu.

Predicateslà các hàm đánh giá một điều kiện và cung cấp giá trị đúng hoặc sai. Chúng ta đã thấy các hàm vị từ trong các ví dụ của chương về số. Chúng tôi đã thấy các chức năng như 'thậm chí?' được sử dụng để kiểm tra xem một số có chẵn hay không, hoặc 'phủ định?' được sử dụng để kiểm tra xem một số có lớn hơn 0 hay không. Tất cả các hàm này đều trả về giá trị true hoặc false.

Sau đây là một ví dụ về các vị từ trong 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)

Chương trình trên tạo ra kết quả sau.

true
false
true
true

Ngoài các chức năng vị ngữ thông thường, Clojure cung cấp thêm các chức năng cho vị ngữ. Các phương pháp sau có sẵn cho các vị từ.

Sr.No. Phương pháp & Mô tả
1 mọi trước

Lấy một tập hợp các vị từ và trả về một hàm 'f' trả về giá trị true nếu tất cả các vị từ tạo thành của nó trả về giá trị đúng logic so với tất cả các đối số của nó, nếu không, hàm trả về false

2 mỗi?

Trả về true nếu vị từ đúng với mọi giá trị, ngược lại là false.

3 một số

Trả về giá trị đúng logic đầu tiên cho bất kỳ giá trị vị từ nào của x trong tập hợp các giá trị.

4 không có?

Trả về false nếu bất kỳ vị từ nào của các giá trị trong một tập hợp là đúng về mặt logic, nếu không thì đúng.

Destructuring là một chức năng trong Clojure, cho phép người ta trích xuất các giá trị từ cấu trúc dữ liệu, chẳng hạn như vectơ và liên kết chúng với các ký hiệu mà không cần phải duyệt qua cấu trúc dữ liệu một cách rõ ràng.

Hãy xem một ví dụ về việc phá hủy chính xác nghĩa là gì và nó diễn ra như thế nào.

Thí dụ

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

Chương trình trên tạo ra kết quả sau.

Đầu ra

1 2 3 4

Trong ví dụ trên, cần lưu ý những điều sau:

  • Chúng tôi đang xác định một vectơ của các số nguyên là 1, 2, 3 và 4.

  • Sau đó chúng tôi đang sử dụng ‘let’ câu lệnh gán 4 biến (a, b, c và d) cho biến my-vector trực tiếp.

  • Nếu chúng tôi chạy ‘println’ trên bốn biến, chúng ta có thể thấy rằng chúng đã được gán cho các giá trị trong vector tương ứng.

Vì vậy, clojure đã hủy biến my-vector có bốn giá trị khi nó được gán bằng câu lệnh 'let'. Sau đó, bốn giá trị đã giải cấu trúc được gán cho bốn tham số tương ứng.

Nếu có các biến dư thừa không có giá trị tương ứng mà chúng có thể được gán, thì chúng sẽ được gán giá trị nil. Ví dụ sau đây làm rõ điểm này.

Thí dụ

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

Chương trình trên tạo ra kết quả sau. Bạn có thể thấy từ đầu ra rằng vì biến cuối cùng 'e' không có giá trị tương ứng trong vectơ, nên nó chiếm tỷ lệ không.

Đầu ra

1 2 3 4 nil

phần còn lại

Biến 'the-rest' được sử dụng để lưu trữ các giá trị còn lại, không thể được gán cho bất kỳ biến nào.

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

Thí dụ

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

Chương trình trên tạo ra kết quả sau. Từ kết quả đầu ra, bạn có thể thấy rõ rằng giá trị 3 và 4 không thể được gán cho bất kỳ biến nào nên chúng được gán cho biến 'the-rest'.

Đầu ra

1 2 (3 4)

Bản đồ cấu trúc

Cũng giống như vectơ, bản đồ cũng có thể bị hủy. Sau đây là một ví dụ về cách có thể thực hiện điều này.

Thí dụ

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

Chương trình trên tạo ra kết quả sau. Từ chương trình, bạn có thể thấy rõ ràng rằng các giá trị ánh xạ của “a” và “b” được gán cho các biến của a và b.

Đầu ra

1 2

Tương tự trong trường hợp vectơ, nếu không có giá trị tương ứng trong bản đồ khi quá trình hủy xảy ra, thì biến sẽ được gán giá trị bằng nil.

Sau đây là một ví dụ.

Thí dụ

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

Chương trình trên tạo ra kết quả sau.

Đầu ra

1 2 nil

Vì khuôn khổ Clojure có nguồn gốc từ các lớp Java, người ta có thể sử dụng các lớp ngày-giờ có sẵn trong Java trong Clojure. Cácclass date đại diện cho một thời điểm cụ thể trong thời gian, với độ chính xác mili giây.

Sau đây là các phương thức có sẵn cho lớp ngày-giờ.

java.util.Date

Điều này được sử dụng để tạo đối tượng ngày tháng trong Clojure.

Cú pháp

Sau đây là cú pháp.

java.util.Date.

Parameters - Không.

Return Value - Phân bổ một đối tượng Date và khởi tạo nó để nó đại diện cho thời gian mà nó đã được cấp phát, được đo chính xác đến từng mili giây.

Thí dụ

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau. Điều này sẽ phụ thuộc vào ngày và giờ hiện tại trên hệ thống mà chương trình đang được chạy.

Tue Mar 01 06:11:17 UTC 2016

java.text.SimpleDateFormat

Điều này được sử dụng để định dạng đầu ra ngày.

Cú pháp

Sau đây là cú pháp.

(java.text.SimpleDateFormat. format dt)

Parameters- 'format' là định dạng được sử dụng khi định dạng ngày tháng. 'dt' là ngày cần được định dạng.

Return Value - Một đầu ra ngày được định dạng.

Thí dụ

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau. Điều này sẽ phụ thuộc vào ngày và giờ hiện tại trên hệ thống mà chương trình đang được chạy.

03/01/2016

dành thời gian

Trả về số mili giây kể từ ngày 1 tháng 1 năm 1970, 00:00:00 GMT được đại diện bởi đối tượng Ngày này.

Cú pháp

Sau đây là cú pháp.

(.getTime)

Parameters - Không.

Return Value - Số mili giây kể từ ngày 1 tháng 1 năm 1970, 00:00:00 GMT được biểu thị bằng ngày này.

Thí dụ

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau. Điều này sẽ phụ thuộc vào ngày và giờ hiện tại trên hệ thống mà chương trình đang được chạy.

1456812778160

Atomslà một kiểu dữ liệu trong Clojure cung cấp cách quản lý trạng thái được chia sẻ, đồng bộ, độc lập. Một nguyên tử cũng giống như bất kỳ kiểu tham chiếu nào trong bất kỳ ngôn ngữ lập trình nào khác. Công dụng chính của nguyên tử là giữ các cấu trúc dữ liệu bất biến của Clojure. Giá trị được giữ bởi một nguyên tử được thay đổi vớiswap! method.

Nội bộ, hoán đổi! đọc giá trị hiện tại, áp dụng chức năng cho nó và cố gắng so sánh và đặt nó vào. Vì một luồng khác có thể đã thay đổi giá trị trong thời gian xen kẽ, nó có thể phải thử lại và làm như vậy trong một vòng quay. Hiệu quả thực là giá trị sẽ luôn là kết quả của việc áp dụng hàm đã cung cấp cho giá trị hiện tại, về mặt nguyên tử.

Thí dụ

Nguyên tử được tạo ra với sự trợ giúp của phương pháp nguyên tử. Một ví dụ tương tự được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

1

Giá trị của nguyên tử được truy cập bằng cách sử dụng ký hiệu @. Clojure có một số hoạt động có thể được thực hiện trên các nguyên tử. Sau đây là các hoạt động.

Sr.No. Hoạt động & Mô tả
1 cài lại!

Đặt giá trị của nguyên tử thành giá trị mới mà không quan tâm đến giá trị hiện tại.

2 so sánh và đặt!

Nguyên tử đặt giá trị của nguyên tử thành giá trị mới khi và chỉ khi giá trị hiện tại của nguyên tử trùng với giá trị cũ mà nguyên tử đó nắm giữ. Trả về true nếu bộ xảy ra, nếu không thì trả về false.

3 hoán đổi!

Nguyên tử hoán đổi giá trị của nguyên tử với một giá trị mới dựa trên một chức năng cụ thể.

Trong Clojure, metadatađược sử dụng để chú thích dữ liệu trong một bộ sưu tập hoặc cho dữ liệu được lưu trữ trong một biểu tượng. Điều này thường được sử dụng để chú thích dữ liệu về các loại cho trình biên dịch bên dưới, nhưng cũng có thể được sử dụng cho các nhà phát triển. Siêu dữ liệu không được coi là một phần của giá trị của đối tượng. Đồng thời, siêu dữ liệu là bất biến.

Có thể thực hiện các thao tác sau trong Clojure liên quan đến siêu dữ liệu.

Sr.No. Hoạt động & Mô tả
1 meta-với

Hàm này được sử dụng để xác định một bản đồ siêu dữ liệu cho bất kỳ đối tượng nào.

2 meta

Hàm này được sử dụng để xem có siêu dữ liệu nào được liên kết với một đối tượng hay không.

3 meta khác nhau

Trả về một đối tượng có cùng kiểu và giá trị với đối tượng ban đầu nhưng có siêu dữ liệu kết hợp.

StructMapsđược sử dụng để tạo cấu trúc trong Clojure. Ví dụ: nếu bạn muốn tạo một cấu trúc bao gồm Tên nhân viên và Nhân viên, bạn có thể làm điều đó với StructMaps.

Các thao tác sau đây có thể thực hiện được trong Clojure liên quan đến StructMaps.

Sr.No. Hoạt động & Mô tả
1 phá hoại

Hàm này được sử dụng để xác định cấu trúc được yêu cầu.

2 cấu trúc

Hàm này được sử dụng để xác định một đối tượng cấu trúc của kiểu, đối tượng này được tạo ra bởi hoạt động defstruct.

3 struct-map

Hàm này được sử dụng để chỉ định cụ thể giá trị cho các giá trị khóa bằng cách xác định rõ ràng giá trị nào được gán cho khóa nào trong cấu trúc.

4 Truy cập các trường riêng lẻ

Các trường riêng lẻ của cấu trúc có thể được truy cập bằng cách truy cập các khóa cùng với đối tượng cấu trúc.

5 Bản chất bất biến

Theo mặc định, cấu trúc cũng không thay đổi, vì vậy nếu chúng ta cố gắng thay đổi giá trị của một khóa cụ thể, nó sẽ không thay đổi.

6 Thêm khóa mới vào cấu trúc

Vì các cấu trúc là bất biến, cách duy nhất mà một khóa khác có thể được thêm vào cấu trúc là thông qua việc tạo một cấu trúc mới. Một ví dụ về cách có thể đạt được điều này được trình bày trong chương trình sau.

Như đã chỉ ra nhiều lần, Clojure là một ngôn ngữ lập trình trong đó nhiều kiểu dữ liệu là bất biến, có nghĩa là cách duy nhất người ta có thể thay đổi giá trị của một biến là tạo một biến mới và gán giá trị mới cho nó. Tuy nhiên, Clojure cung cấp một số yếu tố, có thể tạo ra trạng thái có thể thay đổi. Chúng tôi đã thấy rằng điều này có thể đạt được với kiểu dữ liệu nguyên tử. Cách khác có thể đạt được điều này là thông qua Đại lý.

Agentscung cấp sự thay đổi độc lập, không đồng bộ của các vị trí riêng lẻ. Các tác nhân bị ràng buộc với một vị trí lưu trữ duy nhất trong suốt thời gian tồn tại của họ và chỉ cho phép vị trí đó (sang trạng thái mới) xảy ra đột biến do một hành động. Các hành động là các hàm (với, tùy chọn, các đối số bổ sung) được áp dụng không đồng bộ cho trạng thái của Tác nhân và giá trị trả về của nó trở thành trạng thái mới của Tác nhân.

Các hoạt động sau đây có thể thực hiện được trong Clojure đối với Đại lý.

Sr.No. Hoạt động & Mô tả
1 đặc vụ

Tác nhân được tạo bằng cách sử dụng lệnh tác nhân.

2 gửi

Chức năng này được sử dụng để gửi một giá trị đến tác nhân.

3 tác nhân tắt máy

Chức năng này được sử dụng để tắt mọi tác nhân đang chạy.

4 tiễn đưa

Có những trường hợp trong đó tác nhân được chỉ định một chức năng có bản chất là chặn.

5 đang chờ đợi

Vì có độ trễ khi giá trị của một tác nhân được cập nhật, Clojure đã cung cấp một hàm 'await-for' được sử dụng để chỉ định thời gian tính bằng mili giây để đợi tác nhân được cập nhật.

6 chờ đợi

Chặn luồng hiện tại (vô thời hạn!) Cho đến khi tất cả các hành động được gửi cho đến nay, từ luồng hoặc tác nhân này, đến (các) tác nhân đã xảy ra. Sẽ chặn trên các đại lý không thành công.

7 lỗi tác nhân

Trả về ngoại lệ được đưa ra trong một hành động không đồng bộ của tác nhân, nếu tác nhân không thành công. Trả về nil nếu tác nhân không bị lỗi.

Watcherslà các hàm được thêm vào các kiểu biến như nguyên tử và biến tham chiếu được gọi khi giá trị của kiểu biến thay đổi. Ví dụ: nếu chương trình gọi thay đổi giá trị của một biến nguyên tử và nếu một hàm watcher được gắn với biến nguyên tử, thì hàm sẽ được gọi ngay sau khi giá trị của nguyên tử được thay đổi.

Các chức năng sau có sẵn trong Clojure for Watchers.

add-watch

Thêm một hàm đồng hồ vào tham chiếu agent / atom / var / ref. Đồng hồ‘fn’phải là 'fn' của 4 args: khóa, tham chiếu, trạng thái cũ, trạng thái mới của nó. Bất cứ khi nào trạng thái của tham chiếu có thể bị thay đổi, mọi đồng hồ đã đăng ký sẽ có chức năng của chúng được gọi.

Cú pháp

Sau đây là cú pháp.

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

Parameters- 'biến' là tên của nguyên tử hoặc biến tham chiếu. 'biến kiểu' là loại biến, nguyên tử hoặc biến tham chiếu. 'old-state & new-state' là các tham số sẽ tự động giữ giá trị cũ và mới của biến. 'key' phải là duy nhất cho mỗi tham chiếu và có thể được sử dụng để tháo đồng hồ bằng tháo đồng hồ.

Return Value - Không.

Thí dụ

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

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

tháo đồng hồ

Xóa đồng hồ đã được gắn vào biến tham chiếu.

Cú pháp

Sau đây là cú pháp.

(remove-watch variable watchname)

Parameters- 'biến' là tên của nguyên tử hoặc biến tham chiếu. 'watchname' là tên được đặt cho đồng hồ khi chức năng đồng hồ được xác định.

Return Value - Không.

Thí dụ

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

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

Bạn có thể thấy rõ ràng từ chương trình trên rằng lệnh đặt lại thứ hai không kích hoạt trình theo dõi vì nó đã bị xóa khỏi danh sách của người theo dõi.

Bằng bất kỳ ngôn ngữ nào, Macrosđược sử dụng để tạo mã nội tuyến. Clojure cũng không ngoại lệ và cung cấp các tiện ích vĩ mô đơn giản cho các nhà phát triển. Macro được sử dụng để viết các quy trình tạo mã, cung cấp cho nhà phát triển một cách mạnh mẽ để điều chỉnh ngôn ngữ cho phù hợp với nhu cầu của nhà phát triển.

Sau đây là các phương pháp có sẵn cho Macro.

defmacro

Hàm này được sử dụng để xác định macro của bạn. Macro sẽ có tên macro, danh sách tham số và nội dung của macro.

Cú pháp

Sau đây là cú pháp.

(defmacro name [params*] body)

Parameters- 'name' là tên của macro. 'params' là các tham số được gán cho macro. 'body' là phần thân của macro.

Return Value - Không.

Thí dụ

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

Hello

Từ chương trình trên, bạn có thể thấy rằng macro 'Đơn giản' được mở rộng nội dòng thành 'println' "Xin chào". Macro tương tự như các hàm, với sự khác biệt duy nhất là các đối số của một biểu mẫu được đánh giá trong trường hợp macro.

mở rộng vĩ mô

Điều này được sử dụng để mở rộng macro và đặt mã nội tuyến trong chương trình.

Cú pháp

Sau đây là cú pháp.

(macroexpand macroname)

Parameters - 'macroname' là tên của macro cần được mở rộng.

Return Value - Macro mở rộng.

Thí dụ

Một ví dụ về cách điều này được sử dụng được hiển thị trong chương trình sau.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

Hello

Macro với đối số

Macro cũng có thể được sử dụng để nhận các đối số. Macro có thể nhận bất kỳ số lượng đối số nào. Ví dụ sau trình bày cách sử dụng các đối số.

Thí dụ

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

Ví dụ trên đặt một đối số trong macro Đơn giản và sau đó sử dụng đối số để thêm giá trị đối số vào danh sách.

Đầu ra

Chương trình trên tạo ra kết quả sau.

(2 2)

Reference valueslà một cách khác mà Clojure có thể làm việc với nhu cầu có các biến có thể thay đổi. Clojure cung cấp các kiểu dữ liệu có thể thay đổi như nguyên tử, tác nhân và kiểu tham chiếu.

Sau đây là các hoạt động có sẵn cho các giá trị tham chiếu.

Sr.No. Hoạt động & Mô tả
1 ref

Điều này được sử dụng để tạo một giá trị tham chiếu. Khi tạo một giá trị tham chiếu, có một tùy chọn để cung cấp hàm xác nhận, hàm này sẽ xác thực giá trị được tạo.

2 tái thiết lập

Hàm này được sử dụng để đặt giá trị của một tham chiếu thành một giá trị mới bất kể giá trị cũ hơn là gì.

3 thay đổi

Hàm này được sử dụng để thay đổi giá trị của kiểu tham chiếu nhưng theo cách an toàn. Điều này được chạy trong một chuỗi, không thể được truy cập bởi một quy trình khác.

4 đồng bộ hóa

Chạy biểu thức (trong một hành động ngầm định) trong một giao dịch bao gồm biểu thức và bất kỳ lệnh gọi lồng nhau nào.

5 đường đi làm

Đường đi làm cũng được sử dụng để thay đổi giá trị của loại tham chiếu giống như thay đổi và thiết lập lại.

Để sử dụng chức năng cơ sở dữ liệu, trước tiên hãy đảm bảo tải xuống jdbc files từ url sau - https://codeload.github.com/clojure/java.jdbc/zip/master

Bạn sẽ tìm thấy một tệp zip có các trình điều khiển cần thiết để Clojure có khả năng kết nối với cơ sở dữ liệu. Sau khi tệp zip được giải nén, hãy đảm bảo thêm vị trí đã giải nén vào classpath của bạn.

Tệp chính để kết nối cơ sở dữ liệu là tệp có tên jdbc.clj trong vị trí clojure / java.

Trình kết nối jdbc clojure hỗ trợ nhiều loại cơ sở dữ liệu, một số cơ sở dữ liệu sau.

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

Trong ví dụ của chúng tôi, chúng tôi sẽ sử dụng MySQL DB làm ví dụ.

Các thao tác sau đây có thể thực hiện được trong Clojure liên quan đến Cơ sở dữ liệu.

Kết nối cơ sở dữ liệu

Trước khi kết nối với cơ sở dữ liệu MySQL, hãy đảm bảo những điều sau:

  • Bạn đã tạo một cơ sở dữ liệu TESTDB.

  • Bạn đã tạo một bảng EMPLOYEE trong TESTDB.

  • Bảng này có các trường FIRST_NAME, LAST_NAME, AGE, SEX và THU NHẬP.

  • ID người dùng "testuser" và mật khẩu "test123" được đặt để truy cập TESTDB.

  • Đảm bảo bạn đã tải xuống 'tệp jar mysql' và thêm tệp vào classpath của bạn.

  • Bạn đã xem qua hướng dẫn MySQL để hiểu Cơ bản về MySQL .

Cú pháp

Sau đây là cú pháp để tạo kết nối trong Clojure.

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

Parameters- 'connection_name' là tên được đặt cho kết nối. 'subprotocol' là giao thức được sử dụng cho kết nối. Theo mặc định, chúng tôi sẽ sử dụng giao thức mysql. 'subname' là url để kết nối với db mysql cùng với tên cơ sở dữ liệu. 'user' là tên người dùng được sử dụng để kết nối với cơ sở dữ liệu. 'password' là mật khẩu được sử dụng để kết nối với cơ sở dữ liệu.

Return Value - Điều này sẽ cung cấp một chuỗi kết nối, có thể được sử dụng trong các hoạt động mysql tiếp theo.

Ví dụ sau cho thấy cách kết nối với các bảng trong lược đồ thông tin và truy xuất tất cả dữ liệu trong bảng.

Thí dụ

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

Truy vấn dữ liệu

Truy vấn dữ liệu trên bất kỳ cơ sở dữ liệu nào có nghĩa là lấy một số thông tin hữu ích từ cơ sở dữ liệu. Sau khi kết nối cơ sở dữ liệu được thiết lập, bạn đã sẵn sàng thực hiện truy vấn vào cơ sở dữ liệu này. Sau đây là cú pháp mà dữ liệu có thể được truy vấn bằng cách sử dụng Clojure.

Cú pháp

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

Parameters- 'dbconn' là tên của kết nối được sử dụng để kết nối với cơ sở dữ liệu. 'query' là chuỗi truy vấn được sử dụng để tìm nạp dữ liệu từ cơ sở dữ liệu. ': sequin' theo mặc định là tất cả các hàng dữ liệu được lấy từ cơ sở dữ liệu và được trả về dưới dạng một chuỗi. Các thao tác cần thiết trên chuỗi sau đó có thể được thực hiện để xem dữ liệu nào đã được tìm nạp.

Return Value - Thao tác này sẽ trả về một chuỗi, trong đó sẽ có các hàng dữ liệu từ hoạt động truy vấn.

Ví dụ sau đây cho thấy cách kết nối với bảng nhân viên và tìm nạp cột first_name của các hàng trong bảng.

Thí dụ

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

Từ đoạn mã trên, chúng ta có thể thấy rằng

  • Truy vấn “select first_name từ nhân viên” được chuyển dưới dạng chuỗi truy vấn.

  • : First_name là chuỗi, được trả về là kết quả của hoạt động tìm nạp.

Nếu chúng ta giả sử rằng chỉ có một hàng trong cơ sở dữ liệu của chúng ta chứa giá trị first_name của John, thì sau đây sẽ là đầu ra của chương trình trên.

(John)

Chèn dữ liệu

Nó được yêu cầu khi bạn muốn tạo bản ghi của mình vào một bảng cơ sở dữ liệu. Sau đây là cú pháp mà dữ liệu có thể được chèn bằng Clojure. Điều này được thực hiện bằng cách sử dụng‘insert!’ chức năng.

Cú pháp

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

Parameters- ': table_name' là tên của bảng cần thực hiện chèn. '{: column_namen columnvalue}' là bản đồ của tất cả các tên và giá trị cột cần được thêm vào dưới dạng một hàng trong bảng.

Return Value - Điều này sẽ trả về nil nếu việc chèn được thực hiện thành công.

Ví dụ sau cho thấy cách chèn bản ghi vào bảng nhân viên trong cơ sở dữ liệu testdb.

Thí dụ

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

Nếu bây giờ bạn kiểm tra cơ sở dữ liệu MySQL của mình và bảng nhân viên, bạn sẽ thấy rằng hàng trên sẽ được chèn thành công vào bảng.

Xóa dữ liệu

Có thể xóa hàng khỏi bảng bằng cách sử dụng ‘delete!’chức năng. Sau đây là cú pháp về cách hoạt động này có thể được thực hiện.

Cú pháp

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

Parameters- ': table_name' là tên của bảng cần thực hiện chèn. 'condition' là điều kiện được sử dụng để xác định dòng nào cần được xóa khỏi bảng.

Return Value - Thao tác này sẽ trả về số hàng đã bị xóa.

Ví dụ sau đây cho thấy cách xóa bản ghi khỏi bảng nhân viên trong cơ sở dữ liệu testdb. Ví dụ xóa một hàng khỏi bảng dựa trên điều kiện tuổi bằng 30.

Thí dụ

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

Nếu bạn có một bản ghi có một hàng có tuổi bằng giá trị 30, hàng đó sẽ bị xóa.

Cập nhật dữ liệu

Hàng có thể được cập nhật từ bảng bằng cách sử dụng ‘update!’chức năng. Sau đây là cú pháp về cách hoạt động này có thể được thực hiện.

Cú pháp

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

Parameters- ': table_name' là tên của bảng cần thực hiện chèn. 'setcondition' là cột cần được cập nhật như đã đề cập về bản đồ. 'condition' là điều kiện được sử dụng để xác định hàng nào cần được xóa khỏi bảng.

Return Value - Điều này sẽ trả về số lượng hàng được cập nhật.

Ví dụ sau đây cho thấy cách xóa bản ghi khỏi bảng nhân viên trong cơ sở dữ liệu testdb. Ví dụ cập nhật một hàng từ bảng dựa trên điều kiện tuổi bằng 30 và cập nhật giá trị thu nhập thành 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])))

Nếu bạn có bản ghi có hàng có tuổi bằng giá trị 30, hàng đó sẽ được cập nhật, trong đó giá trị thu nhập sẽ được đặt thành 40.

Giao dịch

Giao dịch là cơ chế đảm bảo tính nhất quán của dữ liệu. Giao dịch có bốn thuộc tính sau:

  • Atomicity - Một giao dịch hoàn tất hoặc không có gì xảy ra cả.

  • Consistency - Một giao dịch phải bắt đầu ở trạng thái nhất quán và để hệ thống ở trạng thái nhất quán.

  • Isolation - Kết quả trung gian của một giao dịch không được hiển thị bên ngoài giao dịch hiện tại.

  • Durability - Một khi giao dịch đã được cam kết, các ảnh hưởng vẫn tồn tại, ngay cả sau khi hệ thống bị lỗi.

Thí dụ

Ví dụ sau đây cho thấy cách thực hiện các giao dịch trong Clojure. Bất kỳ hoạt động nào cần được thực hiện trong một giao dịch cần phải được nhúng vào‘with-dbtransaction’ mệnh đề.

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

Như chúng ta đã biết, mã Clojure chạy trên môi trường ảo Java ở phần cuối. Vì vậy, nó chỉ có ý nghĩa rằng Clojure có thể sử dụng tất cả các chức năng từ Java. Trong chương này, chúng ta hãy thảo luận về mối tương quan giữa Clojure và Java.

Gọi các phương thức Java

Các phương thức Java có thể được gọi bằng cách sử dụng ký hiệu dấu chấm. Một ví dụ là chuỗi. Vì tất cả các chuỗi trong Clojure đều là chuỗi Java, bạn có thể gọi các phương thức Java bình thường trên chuỗi.

Một ví dụ về cách thực hiện điều này được hiển thị trong chương trình sau.

Thí dụ

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

Chương trình trên tạo ra kết quả sau. Bạn có thể thấy từ mã rằng nếu bạn chỉ gọi ký hiệu dấu chấm cho bất kỳ phương thức chuỗi nào, nó cũng sẽ hoạt động trong Clojure.

Đầu ra

HELLO WORLD

Gọi các phương thức Java với các tham số

Bạn cũng có thể gọi các phương thức Java với các tham số. Một ví dụ về cách thực hiện điều này được hiển thị trong chương trình sau.

Thí dụ

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

Chương trình trên tạo ra kết quả sau. Bạn có thể thấy từ đoạn mã trên, rằng chúng tôi đang chuyển tham số “e” cho phương thức indexOf. Chương trình trên tạo ra kết quả sau.

Đầu ra

1

Tạo các đối tượng Java

Các đối tượng có thể được tạo trong Clojure bằng cách sử dụng từ khóa 'mới' tương tự như những gì được thực hiện trong Java.

Một ví dụ về cách thực hiện điều này được hiển thị trong chương trình sau.

Thí dụ

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

Chương trình trên tạo ra kết quả sau. Bạn có thể thấy từ đoạn mã trên, rằng chúng ta có thể sử dụng từ khóa 'mới' để tạo một đối tượng mới từ lớp String hiện có từ Java. Chúng ta có thể truyền giá trị trong khi tạo đối tượng, giống như chúng ta làm trong Java. Chương trình trên tạo ra kết quả sau.

Đầu ra

Hello

Sau đây là một ví dụ khác cho thấy cách chúng ta có thể tạo một đối tượng của lớp Integer và sử dụng chúng trong các lệnh Clojure thông thường.

Thí dụ

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

Chương trình trên tạo ra kết quả sau.

Đầu ra

3

Nhập lệnh

Chúng ta cũng có thể sử dụng lệnh nhập để đưa các thư viện Java vào không gian tên để các lớp và phương thức có thể được truy cập dễ dàng.

Ví dụ sau đây cho thấy cách chúng ta có thể sử dụng lệnh nhập. Trong ví dụ, chúng tôi đang sử dụng lệnh nhập để nhập các lớp từjava.util.stackthư viện. Sau đó, chúng ta có thể sử dụng phương thức push và pop của lớp ngăn xếp như chúng vốn có.

Thí dụ

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

Chương trình trên tạo ra kết quả sau.

Đầu ra

First Element

Chạy mã bằng lệnh Java

Có thể chạy mã Clojure bằng lệnh Java. Sau đây là cú pháp của cách này có thể được thực hiện.

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

Bạn phải đề cập đến tệp jar Clojure, để tất cả các lớp dựa trên Clojure sẽ được tải trong JVM. Tệp 'main.clj' là tệp mã Clojure cần được thực thi.

Các hàm tích hợp trong Java

Clojure có thể sử dụng nhiều hàm có sẵn của Java. Một số trong số họ là -

Math PI function- Clojure có thể sử dụng phương pháp Toán học đến giá trị của PI. Sau đây là một mã ví dụ.

Thí dụ

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

Đoạn mã trên tạo ra kết quả sau.

Đầu ra

3.141592653589793

System Properties- Clojure cũng có thể truy vấn các thuộc tính của hệ thống. Sau đây là một mã ví dụ.

Thí dụ

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

Tùy thuộc vào phiên bản Java trên hệ thống, giá trị tương ứng sẽ được hiển thị. Sau đây là một ví dụ đầu ra.

Đầu ra

1.8.0_45

Trong lập trình Clojure, hầu hết các kiểu dữ liệu là bất biến, do đó khi nói đến lập trình đồng thời, mã sử dụng các kiểu dữ liệu này khá an toàn khi mã chạy trên nhiều bộ xử lý. Nhưng đôi khi, có một yêu cầu chia sẻ dữ liệu và khi nói đến dữ liệu được chia sẻ trên nhiều bộ xử lý, điều cần thiết là đảm bảo rằng trạng thái của dữ liệu được duy trì về tính toàn vẹn khi làm việc với nhiều bộ xử lý. Điều này được gọi làconcurrent programming và Clojure cung cấp hỗ trợ cho việc lập trình như vậy.

Hệ thống bộ nhớ giao dịch phần mềm (STM), được hiển thị thông qua dosync, ref, set, alter, v.v. hỗ trợ chia sẻ trạng thái thay đổi giữa các luồng một cách đồng bộ và phối hợp. Hệ thống tác nhân hỗ trợ chia sẻ trạng thái thay đổi giữa các luồng một cách không đồng bộ và độc lập. Hệ thống nguyên tử hỗ trợ chia sẻ trạng thái thay đổi giữa các luồng một cách đồng bộ và độc lập. Trong khi hệ thống var động, được hiển thị thông qua def, binding, v.v. hỗ trợ cách ly trạng thái thay đổi trong các luồng.

Các ngôn ngữ lập trình khác cũng tuân theo mô hình để lập trình đồng thời.

  • Chúng có một tham chiếu trực tiếp đến dữ liệu có thể được thay đổi.

  • Nếu quyền truy cập chia sẻ được yêu cầu, đối tượng sẽ bị khóa, giá trị bị thay đổi và quá trình tiếp tục cho lần truy cập tiếp theo vào giá trị đó.

Trong Clojure không có ổ khóa, nhưng tham chiếu gián tiếp đến cấu trúc dữ liệu liên tục bất biến.

Có ba loại tham chiếu trong Clojure.

  • Vars - Các thay đổi được cách ly trong chủ đề.

  • Refs - Các thay đổi được đồng bộ và phối hợp giữa các luồng.

  • Agents - Liên quan đến các thay đổi độc lập không đồng bộ giữa các luồng.

Các hoạt động sau đây có thể thực hiện được trong Clojure liên quan đến lập trình đồng thời.

Giao dịch

Đồng tiền trong Clojure dựa trên các giao dịch. Tham chiếu chỉ có thể được thay đổi trong một giao dịch. Các quy tắc sau được áp dụng trong giao dịch.

  • Tất cả các thay đổi là nguyên tử và cô lập.
  • Mọi thay đổi đối với tham chiếu đều xảy ra trong một giao dịch.
  • Không có giao dịch nào nhìn thấy ảnh hưởng của giao dịch khác.
  • Tất cả các giao dịch được đặt bên trong khối dosync.

Chúng ta đã thấy khối dosync có chức năng gì, hãy xem lại nó.

đồng bộ hóa

Chạy biểu thức (trong một hành động ngầm định) trong một giao dịch bao gồm biểu thức và bất kỳ lệnh gọi lồng nhau nào. Bắt đầu một giao dịch nếu không có giao dịch nào đang chạy trên chuỗi này. Bất kỳ trường hợp ngoại lệ không cần thiết nào cũng sẽ hủy bỏ giao dịch và chảy ra khỏi dosync.

Sau đây là cú pháp.

Cú pháp

(dosync expression)

Parameters - 'biểu thức' là tập hợp các biểu thức sẽ nằm trong khối dosync.

Return Value - Không.

Hãy xem một ví dụ trong đó chúng tôi cố gắng thay đổi giá trị của một biến tham chiếu.

Thí dụ

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

Đầu ra

Chương trình trên khi chạy sẽ báo lỗi như sau.

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

Từ lỗi, bạn có thể thấy rõ rằng bạn không thể thay đổi giá trị của loại tham chiếu mà không bắt đầu giao dịch trước.

Để đoạn mã trên hoạt động, chúng ta phải đặt lệnh thay đổi trong một khối dosync như được thực hiện trong chương trình sau.

Thí dụ

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

Chương trình trên tạo ra kết quả sau.

Đầu ra

[John Mark]

Hãy xem một ví dụ khác về dosync.

Thí dụ

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

Trong ví dụ trên, chúng ta có hai giá trị đang được thay đổi trong một khối dosync. Nếu giao dịch thành công, cả hai giá trị sẽ thay đổi, nếu không thì toàn bộ giao dịch sẽ thất bại.

Chương trình trên tạo ra kết quả sau.

Đầu ra

10 20
-10 40

Clojure có một số thư viện đóng góp có khả năng tạo DesktopWeb-based applications. Hãy thảo luận về từng người trong số họ.

Sr.No. Ứng dụng & Mô tả
1 Máy tính để bàn - See-saw

See-saw là một thư viện có thể được sử dụng để tạo các ứng dụng máy tính để bàn.

2 Máy tính để bàn - Thay đổi giá trị của văn bản

Giá trị của nội dung trong cửa sổ có thể được thay đổi bằng cách sử dụng ‘config!’Lựa chọn. Trong ví dụ sau, cấu hình! được sử dụng để thay đổi nội dung cửa sổ thành giá trị mới của “Good Bye”.

3 Máy tính để bàn - Hiển thị Hộp thoại Phương thức

Hộp thoại phương thức có thể được hiển thị bằng cách sử dụng phương thức cảnh báo của lớp see-saw. Phương thức này nhận giá trị văn bản, giá trị này cần được hiển thị trong hộp thoại phương thức.

4 Máy tính để bàn - Các nút hiển thị

Các nút có thể được hiển thị với sự trợ giúp của lớp nút.

5 Máy tính để bàn - Hiển thị Nhãn

Các nhãn có thể được hiển thị với sự trợ giúp của lớp nhãn.

6 Máy tính để bàn - Hiển thị các trường văn bản

Trường Văn bản có thể được hiển thị với sự trợ giúp của lớp văn bản.

Ứng dụng web - Giới thiệu

Để tạo một ứng dụng web trong Clojure, bạn cần sử dụng thư viện ứng dụng Ring, có sẵn tại liên kết sau https://github.com/ring-clojure/ring

Bạn cần đảm bảo rằng bạn tải xuống các lọ cần thiết từ trang web và đảm bảo thêm nó làm phụ thuộc cho ứng dụng Clojure.

Các Ring framework cung cấp các khả năng sau:

  • Thiết lập mọi thứ sao cho một yêu cầu http đi vào ứng dụng web của bạn dưới dạng một Clojure HashMap thông thường, và tương tự như vậy, làm cho nó để bạn có thể trả lại phản hồi dưới dạng HashMap.

  • Cung cấp thông số kỹ thuật mô tả chính xác các bản đồ yêu cầu và phản hồi đó trông như thế nào.

  • Mang theo một máy chủ web (Jetty) và kết nối ứng dụng web của bạn với nó.

Ring framework tự động có thể khởi động máy chủ web và đảm bảo ứng dụng Clojure hoạt động trên máy chủ này. Sau đó, người ta cũng có thể sử dụng khung Compojure. Điều này cho phép người ta tạo các tuyến đường mà hiện nay là cách hầu hết các ứng dụng web hiện đại được phát triển.

Creating your first Clojure application - Ví dụ sau đây cho thấy cách bạn có thể tạo ứng dụng web đầu tiên của mình trong 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))

Hãy cùng xem xét các khía cạnh sau của chương trình -

  • Các ‘defroutes’ được sử dụng để tạo các tuyến sao cho yêu cầu được gửi đến ứng dụng web đến các tuyến khác nhau có thể được chuyển hướng đến các chức năng khác nhau trong ứng dụng Clojure của bạn.

  • Trong ví dụ trên, “/” được gọi là đường dẫn mặc định, vì vậy khi bạn duyệt đến cơ sở ứng dụng web của mình, chuỗi “Hello World” sẽ được gửi đến trình duyệt web.

  • Nếu người dùng truy cập vào bất kỳ url nào mà ứng dụng Clojure không thể xử lý, thì nó sẽ hiển thị chuỗi “Không tìm thấy”.

Khi bạn chạy ứng dụng Clojure, theo mặc định, ứng dụng của bạn sẽ được tải dưới dạng localhost: 3000, vì vậy nếu bạn duyệt đến vị trí này, bạn sẽ nhận được kết quả sau.

Ứng dụng web - Thêm nhiều tuyến đường vào ứng dụng web của bạn

Bạn cũng có thể thêm nhiều tuyến đường hơn vào ứng dụng web của mình. Ví dụ sau đây cho thấy làm thế nào để đạt được điều này.

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

Bạn có thể thấy rằng việc thêm một tuyến đường trong ứng dụng cũng dễ dàng như chỉ cần thêm một hàm GET khác với tuyến đường url. (GET "/ Tutorial" [] "Đây là một hướng dẫn về Clojure")

Nếu bạn duyệt đến vị trí http://localhost:3000/Tutorial, bạn sẽ nhận được kết quả sau.

Trong chương này, hãy thảo luận về các tùy chọn kiểm thử tự động do Clojure cung cấp.

Kiểm tra ứng dụng khách

Để sử dụng thử nghiệm cho khuôn khổ Clojure, bạn phải sử dụng các phần phụ thuộc tại https://github.com/slagyr/speclj#manual-installation

URL này cung cấp specljkhung, được sử dụng làm khung thử nghiệm theo hướng dữ liệu Thử nghiệm hoặc theo hướng hành vi cho Clojure. Bạn phải đảm bảo rằng bạn sử dụng khuôn khổ Clojure 1.7.0 khi sử dụng bất kỳ thư viện 'speclj' nào. Theo mặc định, các tệp kiểm tra sẽ khác với tệp mã Clojure và cần được đặt trong thư mục 'spec'.

Sau đây là mã mẫu cho một tệp thử nghiệm.

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

Những điều sau đây cần được lưu ý về đoạn mã trên:

  • Trước tiên, chúng ta phải đảm bảo sử dụng câu lệnh 'request' để bao gồm tất cả các thư viện cốt lõi trong khuôn khổ 'speclj'.

  • Tiếp theo là chức năng 'mô tả'. Điều này được sử dụng để cung cấp mô tả cho trường hợp thử nghiệm đang được tạo.

  • Chức năng tiếp theo là chức năng 'it', là trường hợp thử nghiệm thực tế. Trong trường hợp thử nghiệm đầu tiên, chuỗi “là đúng” là tên được đặt cho trường hợp thử nghiệm.

  • Nên và không nên được gọi là assertions. Tất cả các khẳng định đều bắt đầu bằng nên. Nên và không nên chỉ là hai trong số rất nhiều khẳng định có sẵn. Cả hai đều sử dụng các biểu thức mà họ sẽ kiểm tra sự thật và giả mạo tương ứng.

Nếu bạn chạy trường hợp thử nghiệm, bạn sẽ nhận được kết quả sau. Đầu ra hiển thị thời gian tính bằng mili giây để chạy trường hợp thử nghiệm.

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

Kiểm tra các ứng dụng dựa trên web

Seleniumlà một trong những khuôn khổ quan trọng được sử dụng để thử nghiệm các ứng dụng dựa trên web hiện đại. Thư viện clojure cũng có sẵn, có thể được sử dụng để thử nghiệm các ứng dụng dựa trên web.

Hãy xem cách chúng ta có thể sử dụng các thư viện Selenium để thử nghiệm các ứng dụng dựa trên web Clojure.

Step 1- Bước đầu tiên là đảm bảo chúng ta đang sử dụng khuôn khổ Ring và Compojure để tạo một ứng dụng dựa trên web, cần được thử nghiệm. Hãy sử dụng một trong những ví dụ từ các chương trước của chúng tôi. Đoạn mã sau là một ứng dụng web đơn giản, hiển thị "Hello World" trong trình duyệt.

(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 - Tiếp theo, hãy đảm bảo tải xuống tệp jar selen https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server/2.47.0 và đưa nó vào classpath của bạn.

Step 3 - Cũng đảm bảo tải xuống trình điều khiển web 'clj', trình điều khiển này sẽ được sử dụng để chạy kiểm tra web từ vị trí sau.

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

Step 4 - Trong thư mục dự án của bạn, hãy tạo một thư mục khác có tên là các tính năng và tạo một tệp có tên 'config.clj'.

Step 5 - Tiếp theo, thêm đoạn mã sau vào tệp 'config.clj' đã tạo ở bước trước đó.

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

Đoạn mã trên về cơ bản cho khung kiểm tra web kiểm tra ứng dụng, được tải tại URL http://localhost:3000

Step 6 - Cuối cùng, chúng ta hãy viết mã của chúng ta để thực hiện thử nghiệm của chúng ta.

(ns clj-webdriver-tutorial.features.homepage
   (:require [clojure.test :refer :all]
      [ring.adapter.jetty :refer [run-jetty]]
      [clj-webdriver.taxi :refer :all]
      [clj-webdriver-tutorial.features.config :refer :all]
      [clj-webdriver-tutorial.handler :refer [app-routes]]))
(ns clj-webdriver-tutorial.features.homepage
   (:require [clojure.test :refer :all]
      [ring.adapter.jetty :refer [run-jetty]]
      [clj-webdriver.taxi :refer :all]
      [clj-webdriver-tutorial.features.config :refer :all]
      [clj-webdriver-tutorial.handler :refer [app-routes]]))
(defn start-server []
   (loop [server (run-jetty app-routes {:port test-port, :join? false})]
      (if (.isStarted server)
         server
         (recur server))))
(defn stop-server [server]
   (.stop server))
(defn start-browser []
   (set-driver! {:browser :firefox}))
(defn stop-browser []
   (quit))
(deftest homepage-greeting
   (let [server (start-server)]
      (start-browser)
      (to test-base-url)
      (is (= (text "body") "Hello World"))
      (stop-browser)
      (stop-server server)))

Đoạn mã trên sẽ thực hiện các hành động sau:

  • Khởi động máy chủ cho ứng dụng.
  • Mở đường dẫn gốc trong trình duyệt.
  • Kiểm tra xem thông báo "Hello World" có trên trang hay không.
  • Đóng trình duyệt.
  • Tắt máy chủ.

Một điều làm cho thư viện Clojure trở nên mạnh mẽ là số lượng thư viện có sẵn cho khuôn khổ Clojure. Chúng tôi đã thấy rất nhiều thư viện được sử dụng trong các ví dụ trước đó của chúng tôi để kiểm tra web, phát triển web, phát triển các ứng dụng dựa trên swing, thư viện jdbc để kết nối với cơ sở dữ liệu MySQL. Sau đây chỉ là một vài ví dụ về một vài thư viện khác.

data.xml

Thư viện này cho phép Clojure làm việc với dữ liệu XML. Phiên bản thư viện được sử dụng là org.clojure / data.xml "0.0.8". Data.xml hỗ trợ phân tích cú pháp và tạo ra XML. Các hàm phân tích cú pháp sẽ đọc XML từ Reader hoặc InputStream.

Thí dụ

Sau đây là một ví dụ về xử lý dữ liệu từ một chuỗi sang 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

Thư viện này cho phép Clojure hoạt động với dữ liệu JSON. Phiên bản thư viện được sử dụng là org.clojure / data.json "0.2.6".

Thí dụ

Sau đây là một ví dụ về việc sử dụng thư viện này.

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

Đầu ra

Chương trình trên tạo ra kết quả sau.

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

data.csv

Thư viện này cho phép Clojure làm việc với ‘csv’dữ liệu. Phiên bản thư viện sẽ được sử dụng là org.clojure / data.csv "0.1.3".

Thí dụ

Sau đây là một ví dụ về việc sử dụng thư viện này.

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

Trong đoạn mã trên, hàm 'csv' trước tiên sẽ đọc một tệp có tên in-file.csvvà đưa tất cả dữ liệu vào biến trong tệp. Tiếp theo, chúng tôi đang sử dụng hàm write-csv để ghi tất cả dữ liệu vào một tệp có tênout-file.csv.