日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Y分钟学clojure

發(fā)布時(shí)間:2025/6/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Y分钟学clojure 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Clojure是運(yùn)行在JVM上的Lisp家族中的一員。她比Common Lisp更強(qiáng)調(diào)純函數(shù)式編程,且自發(fā)布時(shí)便包含了一組工具來(lái)處理狀態(tài)。

這種組合讓她能十分簡(jiǎn)單且自動(dòng)地處理并發(fā)問(wèn)題。

(你需要使用Clojure 1.2或更新的發(fā)行版)

; 注釋以分號(hào)開(kāi)始。

Clojure代碼由一個(gè)個(gè)form組成, 即寫在小括號(hào)里的由空格分開(kāi)的一組語(yǔ)句。
Clojure解釋器會(huì)把第一個(gè)元素當(dāng)做一個(gè)函數(shù)或者宏來(lái)調(diào)用,其余的被認(rèn)為是參數(shù)。

Clojure代碼的第一條語(yǔ)句一般是用ns來(lái)指定當(dāng)前的命名空間。

(ns learnclojure)

str會(huì)使用所有參數(shù)來(lái)創(chuàng)建一個(gè)字符串

(str "Hello" " " "World") ; => "Hello World"

數(shù)學(xué)計(jì)算比較直觀

(+ 1 1) ; => 2 (- 2 1) ; => 1 (* 1 2) ; => 2 (/ 2 1) ; => 2

等號(hào)是?=

(= 1 1) ; => true (= 2 1) ; => false

邏輯非

(not true) ; => false

嵌套的form工作起來(lái)應(yīng)該和你預(yù)想的一樣

(+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2

類型

Clojure使用Java的Object來(lái)描述布爾值、字符串和數(shù)字
用函數(shù)?class?來(lái)查看具體的類型

(class 1) ; 整形默認(rèn)是java.lang.Long類型 (class 1.); 浮點(diǎn)默認(rèn)是java.lang.Double類型的 (class ""); String是java.lang.String類型的,要用雙引號(hào)引起來(lái) (class false) ; 布爾值是java.lang.Boolean類型的 (class nil); "null"被稱作nil

如果你想創(chuàng)建一組數(shù)據(jù)字面量,用單引號(hào)(')來(lái)阻止form被解析和求值

'(+ 1 2) ; => (+ 1 2)

單引號(hào)是quote的簡(jiǎn)寫形式,故上式等價(jià)于(quote (+ 1 2))

可以對(duì)一個(gè)引用列表求值

(eval '(+ 1 2)) ; => 3

集合(Collection)和序列

List的底層實(shí)現(xiàn)是鏈表,Vector的底層實(shí)現(xiàn)是數(shù)組
二者也都是java類

(class [1 2 3]); => clojure.lang.PersistentVector (class '(1 2 3)); => clojure.lang.PersistentList

list本可以寫成(1 2 3), 但必須用引用來(lái)避免被解釋器當(dāng)做函數(shù)來(lái)求值。
(list 1 2 3)等價(jià)于'(1 2 3)

集合其實(shí)就是一組數(shù)據(jù)
List和Vector都是集合:

(coll? '(1 2 3)) ; => true (coll? [1 2 3]) ; => true

序列 (seqs) 是數(shù)據(jù)列表的抽象描述
只有列表才可稱作序列。

(seq? '(1 2 3)) ; => true (seq? [1 2 3]) ; => false

序列被訪問(wèn)時(shí)只需要提供一個(gè)值,所以序列可以被惰性加載——也就意味著可以定義一個(gè)無(wú)限序列:

(range 4) ; => (0 1 2 3) (range) ; => (0 1 2 3 4 ...) (無(wú)限序列) (take 4 (range)) ; (0 1 2 3)

cons用以向列表或向量的起始位置添加元素

(cons 4 [1 2 3]) ; => (4 1 2 3) (cons 4 '(1 2 3)) ; => (4 1 2 3)

conj將以最高效的方式向集合中添加元素。
對(duì)于列表,數(shù)據(jù)會(huì)在起始位置插入,而對(duì)于向量,則在末尾位置插入。

(conj [1 2 3] 4) ; => [1 2 3 4] (conj '(1 2 3) 4) ; => (4 1 2 3)

用concat來(lái)合并列表或向量

(concat [1 2] '(3 4)) ; => (1 2 3 4)

用filter來(lái)過(guò)濾集合中的元素,用map來(lái)根據(jù)指定的函數(shù)來(lái)映射得到一個(gè)新的集合

(map inc [1 2 3]) ; => (2 3 4) (filter even? [1 2 3]) ; => (2)

recuce使用函數(shù)來(lái)規(guī)約集合

(reduce + [1 2 3 4]) ; = (+ (+ (+ 1 2) 3) 4) ; => 10

reduce還能指定一個(gè)初始參數(shù)

(reduce conj [] '(3 2 1)) ; = (conj (conj (conj [] 3) 2) 1) ; => [3 2 1]

函數(shù)

用fn來(lái)創(chuàng)建函數(shù)。函數(shù)的返回值是最后一個(gè)表達(dá)式的值

(fn [] "Hello World") ; => fn

你需要再嵌套一組小括號(hào)來(lái)調(diào)用它

((fn [] "Hello World")) ; => "Hello World"

你可以用def來(lái)創(chuàng)建一個(gè)變量(var)

(def x 1) x ; => 1

將函數(shù)定義為一個(gè)變量(var)

(def hello-world (fn [] "Hello World")) (hello-world) ; => "Hello World"

你可用defn來(lái)簡(jiǎn)化函數(shù)的定義

(defn hello-world [] "Hello World")

中括號(hào)內(nèi)的內(nèi)容是函數(shù)的參數(shù)。

(defn hello [name](str "Hello " name)) (hello "Steve") ; => "Hello Steve"

你還可以用這種簡(jiǎn)寫的方式來(lái)創(chuàng)建函數(shù):

(def hello2 #(str "Hello " %1)) (hello2 "Fanny") ; => "Hello Fanny"

函數(shù)也可以有多個(gè)參數(shù)列表。

(defn hello3([] "Hello World")([name] (str "Hello " name))) (hello3 "Jake") ; => "Hello Jake" (hello3) ; => "Hello World"

可以定義變參函數(shù),即把&后面的參數(shù)全部放入一個(gè)序列

(defn count-args [& args](str "You passed " (count args) " args: " args)) (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)"

可以混用定參和變參(用&來(lái)界定)

(defn hello-count [name & args](str "Hello " name ", you passed " (count args) " extra args")) (hello-count "Finn" 1 2 3) ; => "Hello Finn, you passed 3 extra args"

哈希表

基于hash的map和基于數(shù)組的map(即arraymap)實(shí)現(xiàn)了相同的接口,hashmap查詢起來(lái)比較快,
但不保證元素的順序。

(class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap (class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap

arraymap在足夠大的時(shí)候,大多數(shù)操作會(huì)將其自動(dòng)轉(zhuǎn)換成hashmap,
所以不用擔(dān)心(對(duì)大的arraymap的查詢性能)。

map支持很多類型的key,但推薦使用keyword類型
keyword類型和字符串類似,但做了一些優(yōu)化。

(class :a) ; => clojure.lang.Keyword(def stringmap {"a" 1, "b" 2, "c" 3}) stringmap ; => {"a" 1, "b" 2, "c" 3}(def keymap {:a 1, :b 2, :c 3}) keymap ; => {:a 1, :c 3, :b 2}

順便說(shuō)一下,map里的逗號(hào)是可有可無(wú)的,作用只是提高map的可讀性。

從map中查找元素就像把map名作為函數(shù)調(diào)用一樣。

(stringmap "a") ; => 1 (keymap :a) ; => 1

可以把keyword寫在前面來(lái)從map中查找元素。

(:b keymap) ; => 2

但不要試圖用字符串類型的key來(lái)這么做。

("a" stringmap) ; => Exception: java.lang.String cannot be cast to clojure.lang.IFn

查找不存在的key會(huì)返回nil。

(stringmap "d") ; => nil

用assoc函數(shù)來(lái)向hashmap里添加元素

(def newkeymap (assoc keymap :d 4)) newkeymap ; => {:a 1, :b 2, :c 3, :d 4}

但是要記住的是clojure的數(shù)據(jù)類型是不可變的!

keymap ; => {:a 1, :b 2, :c 3}

用dissoc來(lái)移除元素

(dissoc keymap :a :b) ; => {:c 3}

集合(Set)

(class #{1 2 3}) ; => clojure.lang.PersistentHashSet (set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3}

用conj新增元素

(conj #{1 2 3} 4) ; => #{1 2 3 4}

用disj移除元素

(disj #{1 2 3} 1) ; => #{2 3}

把集合當(dāng)做函數(shù)調(diào)用來(lái)檢查元素是否存在:

(#{1 2 3} 1) ; => 1 (#{1 2 3} 4) ; => nil

在clojure.sets模塊下有很多相關(guān)函數(shù)。

常用的form

clojure里的邏輯控制結(jié)構(gòu)都是用宏(macro)實(shí)現(xiàn)的,這在語(yǔ)法上看起來(lái)沒(méi)什么不同。

(if false "a" "b") ; => "b" (if false "a") ; => nil

用let來(lái)創(chuàng)建臨時(shí)的綁定變量。

(let [a 1 b 2](> a b)) ; => false

用do將多個(gè)語(yǔ)句組合在一起依次執(zhí)行

(do(print "Hello")"World") ; => "World" (prints "Hello")

函數(shù)定義里有一個(gè)隱式的do

(defn print-and-say-hello [name](print "Saying hello to " name)(str "Hello " name)) (print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff")

let也是如此

(let [name "Urkel"](print "Saying hello to " name)(str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel")

模塊

用use來(lái)導(dǎo)入模塊里的所有函數(shù)

(use 'clojure.set)

然后就可以使用set相關(guān)的函數(shù)了

(intersection #{1 2 3} #{2 3 4}) ; => #{2 3} (difference #{1 2 3} #{2 3 4}) ; => #{1}

你也可以從一個(gè)模塊里導(dǎo)入一部分函數(shù)。

(use '[clojure.set :only [intersection]])

用require來(lái)導(dǎo)入一個(gè)模塊

(require 'clojure.string)

用/來(lái)調(diào)用模塊里的函數(shù)
下面是從模塊clojure.string里調(diào)用blank?函數(shù)。

(clojure.string/blank? "") ; => true

在import里你可以給模塊名指定一個(gè)較短的別名。

(require '[clojure.string :as str]) (str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst."

#""用來(lái)表示一個(gè)正則表達(dá)式

你可以在一個(gè)namespace定義里用:require的方式來(lái)require(或use,但最好不要用)模塊。
這樣的話你無(wú)需引用模塊列表。

(ns test(:require[clojure.string :as str][clojure.set :as set]))

Java

Java有大量的優(yōu)秀的庫(kù),你肯定想學(xué)會(huì)如何用clojure來(lái)使用這些Java庫(kù)。

用import來(lái)導(dǎo)入java類

(import java.util.Date)

也可以在ns定義里導(dǎo)入

(ns test(:import java.util.Datejava.util.Calendar))

用類名末尾加.的方式來(lái)new一個(gè)Java對(duì)象

(Date.) ; <a date object>

用.操作符來(lái)調(diào)用方法,或者用.method的簡(jiǎn)化方式。

(. (Date.) getTime) ; <a timestamp> (.getTime (Date.)) ; 和上例一樣。

用/調(diào)用靜態(tài)方法

(System/currentTimeMillis) ; <a timestamp> (system is always present)

用doto來(lái)更方便的使用(可變)類。

(import java.util.Calendar) (doto (Calendar/getInstance)(.set 2000 1 1 0 0 0).getTime) ; => A Date. set to 2000-01-01 00:00:00

STM

軟件內(nèi)存事務(wù)(Software Transactional Memory)被clojure用來(lái)處理持久化的狀態(tài)。
clojure里內(nèi)置了一些結(jié)構(gòu)來(lái)使用STM。
atom是最簡(jiǎn)單的。給它傳一個(gè)初始值

(def my-atom (atom {}))

用swap!更新atom。
swap!會(huì)以atom的當(dāng)前值為第一個(gè)參數(shù)來(lái)調(diào)用一個(gè)指定的函數(shù),
swap其余的參數(shù)作為該函數(shù)的第二個(gè)參數(shù)。

(swap! my-atom assoc :a 1) ; Sets my-atom to the result of (assoc {} :a 1) (swap! my-atom assoc :b 2) ; Sets my-atom to the result of (assoc {:a 1} :b 2)

用@讀取atom的值

my-atom ;=> Atom<#...> (返回Atom對(duì)象) @my-atom ; => {:a 1 :b 2}

下例是一個(gè)使用atom實(shí)現(xiàn)的簡(jiǎn)單計(jì)數(shù)器

(def counter (atom 0)) (defn inc-counter [](swap! counter inc))(inc-counter) (inc-counter) (inc-counter) (inc-counter) (inc-counter)@counter ; => 5

其他STM相關(guān)的結(jié)構(gòu)是ref和agent.
; Refs:?http://clojure.org/refs
; Agents:?http://clojure.org/agents

進(jìn)階讀物

本文肯定不足以講述關(guān)于clojure的一切,但是希望足以讓你邁出第一步。

Clojure.org官網(wǎng)有很多文章:
http://clojure.org/

Clojuredocs.org有大多數(shù)核心函數(shù)的文檔,還帶了示例哦:
http://clojuredocs.org/quickref/Clojure%20Core

4Clojure是個(gè)很贊的用來(lái)練習(xí)clojure/FP技能的地方:
http://www.4clojure.com/

Clojure-doc.org 有很多入門級(jí)的文章:
http://clojure-doc.org/

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的Y分钟学clojure的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。