前言
?每逢學(xué)習(xí)一個新的語言時總要先了解這門語言支持的數(shù)據(jù)類型,因為數(shù)據(jù)類型決定這門語言所針對的問題域,像Bash那樣內(nèi)置只支持字符串的腳步明顯就是用于文本處理啦。而數(shù)據(jù)類型又分為標(biāo)量類型(Scalar)、結(jié)構(gòu)類型(Struct)和集合類型(Collection),標(biāo)題中的簡單類型實質(zhì)就是指標(biāo)量類型。
?cljs中內(nèi)置的標(biāo)量類型比js的豐富得多,一方面方便了操作,另一個方面增加了學(xué)習(xí)成本,因此從js轉(zhuǎn)向cljs時可能會略感不適,下面我們一起來認(rèn)識吧!
標(biāo)量類型一覽
;; 空值/空集nil;; 字符串,必須使用雙引號包裹"I am a string!";; 字符,以斜桿開頭 \& \newline ;; 布爾類型(Boolean),nil隱式類型轉(zhuǎn)換為false,0和空字符串等均隱式類型轉(zhuǎn)換為truetruefalse;; 長整型(Long)1;; 浮點型(Float)1.2;; 整型十六進(jìn)制0x0000ff;; 指數(shù)表示法1.2e3 ;; 鍵(Keyword),以:為首字符,一般用于Map作為key:i-am-a-key;; Symbol,標(biāo)識符 i-am-symbol ;; Var i-am-var ;; Special Form ;; 如if, let, do等 (if pred then else?) (let [a 1] expr1 expr2) (do expr*) ;; 函數(shù) (fn [a] (println a)) ;; 宏 (defmacro out [s] `(println ~s))
Keyword真心不簡單??!
?位于cljs.core/Keyword
的關(guān)鍵字并不是僅僅如上述那樣簡單,其實一共有3種定義方式:
1.所見即所得
;; 通過literal來定義:i-am-a-keyword:i-am-a-namespace/i-am-a-keyword;; 通過keyword函數(shù)來定義 (keyword "i-am-a-keyword") (keyword "i-am-a-namespace" "i-am-a-keyword")
2.自動擴(kuò)展為以當(dāng)前命名空間為前綴
(ns cljs.user) ;; 自動擴(kuò)展為以當(dāng)前命名空間為前綴的keywork::keyword ;;=> :cljs.user/keyword
3.自動擴(kuò)展為
;; 自動查找以aliased-ns為別名的命名空間,并以找到的命名空間作為前綴創(chuàng)建keyword ;; 因此需要先通過require 引入命名空間才能通過別名解析出原來的命名空間 (ns cljs.user (:require '[test.core :as test])) ::test/keyword ;;=> :test.core/my-keyword
另外Keyword還可以作為函數(shù)使用呢!
(def person {:name "fsjohnhuang", "sex" "male"}) (:name person) ;;=> "fsjohnhuang"("sex" person) ;;=> 報錯(get person "sex") ;;=> "male"
什么是Symbol?
?在任何Lisp方言中Symbol作為標(biāo)識符(Identity),如命名空間名稱、函數(shù)名稱、變量名稱、Special Form名稱等等。而凡是標(biāo)識符均會被限制可使用的字符集范圍,那么合法的cljs.core/Symbol
需遵守以下規(guī)則:
首字符不能是
[0-9:]
后續(xù)字符可為
[a-zA-Z0-9*+-_!?|:=<>$&]
末尾字符不能是
:
區(qū)分大小寫
?命名習(xí)慣:
全小寫
單詞間以
-
分隔常量和全局標(biāo)識,首尾為
*
,如*main-cli-fn*
*x
,標(biāo)識內(nèi)置變量,且經(jīng)常值變化x?
,標(biāo)識斷言函數(shù)x!
,標(biāo)識產(chǎn)生副作用的函數(shù)x-
,標(biāo)識其將產(chǎn)生私有方法,如defn-
和deftest-
_
,標(biāo)識可忽略的symbol
既然Symbol僅僅作為標(biāo)識符來使用,為何不見JS、C#等會將標(biāo)識符獨立出來作為一種類型呢?原因十分簡單但又難以理解——Lisp中代碼即數(shù)據(jù),數(shù)據(jù)即代碼。作為Lisp的方言cljs自然傳承了這一耀眼的特性!
;; 定義一個List實例,其元素為a和b兩個Symbol實例(def symbol-list (list 'a 'b))
?大家有沒有注意到'
這個符號???由于symbol根據(jù)它在列表中的位置解析為Special Form或Var,為阻止這一過程需要通過quote
函數(shù)來處理,而'
就是quote
的reader macro。不信大家試試(cljs.reader/read-string "'a")
它會擴(kuò)展為(cljs.core/quote a)
另外
;; 判斷是否為cljs.core/Symbol類型(symbol? 'a) ;;=> true;; symbol可以作為函數(shù)使用(def a {'b 1}) ('b a) ;;=> 1
Var又是什么呢?
?在clj/cljs中Var是一個容器,其內(nèi)容為指向?qū)嶋H值的地址,當(dāng)其內(nèi)容為nil時稱之為unbound,非nil時則稱為bound。而一個Var可以對應(yīng)1~N個Symbol。
;; Symbol a和b都對應(yīng)同一個Var,這個Var指向1所在的內(nèi)存地址(def a 1) (def b 1)
這個和JAVA、C#中的String是一樣的。另外Clojure還有一個十分有趣的特性就是Symbol直接綁定值,中間沒有Var,因此就不存在重新賦值的可能
(defn say [s] (println s)) (defn say1 [s] (def s 2) (println s)) (say "say") ;;=> say(say1 "say1") ;;=> say1
和Symbol同樣,Var可以作為數(shù)據(jù)處理,不過由于Var會根據(jù)其所在列表中的位置解析為是Macro還是函數(shù)還是值,因此需要通過#'
來阻止,而#'
就是var
的reader macro。
(def b 1) (def c 2) (def a (list #'b #'c))
注意:#'
或var
操作前必須要先定義好同名變量、內(nèi)置或第三方庫已定義的變量,否則會報錯。
Special Form又是什么鬼?
?實質(zhì)上就是語言原語,其他函數(shù)和Macro均基于它們來構(gòu)造,當(dāng)解析器遇到一個Symbol時會解析的順序是Special Form
-> Var
。
如if
就是一個原語,即使是Macro也沒有辦法從無來構(gòu)造一個,不信大家自己試試吧!
部分常用的Special Form如下:
(def symbol init?) (if test then else?) (do exprs*) (let [binding*] exprs*) (quote form) (var symbol) (fn name? [params*] exprs*) (fn name? ([params*] exprs*)+) (fn name? [params*] condition-map? exprs*) (fn name? ([params*] condition-map? exprs*)+) (loop [binding*] exprs*) (recur exprs*) (throw expr) (try expr* catch-clause* finally-clause?)
怎么函數(shù)也納入標(biāo)量呢?
?函數(shù)式編程當(dāng)中第一條規(guī)則就是“函數(shù)是一等公民”,就是函數(shù)和String、Integer等一樣可以作入?yún)?、函?shù)返回值,更確切來說函數(shù)的構(gòu)造不依賴其他類型或類型實例。而面向?qū)ο笾?,沒有函數(shù)只有方法,而方法的構(gòu)造前必須先構(gòu)建其所依賴的類型或類型實例。
?另外cljs中確實是用定義變量的方式來定義函數(shù)
(defn a [x] (println x));; defn是macro,實質(zhì)上會展開成(def a (fn [x] (println x)))
是不是清楚多了??!
總結(jié)
?本文較詳盡地介紹了Keyword,然后稍微介紹了Symbol、Var和Special Form,而Lisp中“代碼即數(shù)據(jù),數(shù)據(jù)即代碼”需要結(jié)合Symbol的解釋過程說明效果才有所體現(xiàn),這個由于篇幅較大,就打算日后再另起一篇來描述了。
?作為函數(shù)式編程語言,cljs的函數(shù)定義又怎么會只有(defn name [params*] exprs*)
呢?下一篇(cljs/run-at (JSVM. :all) "細(xì)說函數(shù)"),我們一起細(xì)說吧!
尊重原創(chuàng),轉(zhuǎn)載請注明來自:http://www.cnblogs.com/fsjohnhuang/p/7119333.html ^_^肥仔John
REF
http://www.cnblogs.com/or2-/p/3579745.html
如果您覺得本文的內(nèi)容有趣就掃一下吧!捐贈互勉!
??
http://www.cnblogs.com/fsjohnhuang/p/7119333.html