今天是深夜模式,走凌晨發文路線~
在Clojure裡Map類似Python的Disctionary, Ruby的Hash和Javascript的Object。
| Javascript | Clojurescript | 
|---|---|
| Object {a: 1, b: 2} | Map {:a 1, :b 2} | 
JS Console:

Clojure的Map:
你會問,那前面有冒號:的是什麼呢?那叫做Keyword
tutorial.core=> {}
{}
tutorial.core=> {:a 1, :b 2 }
{:a 1, :b 2}
昨天的鐵人賽文章有講到用來取Vector的值可以用get
 (get ["the Philosopher's Stone" "the Chamber of Secrets" "the Prisoner of Azkaban"] 2)
"the Prisoner of Azkaban"
取Map得值,要用的是keyword
(get {:c {:a 1, :b 2}} :c)
=>{:a 1, :b 2}
但如果我們視{}Map為一個function的話,get也可以省略
({:c {:a 1, :b 2}} :c)
=> {:a 1, :b 2}
map也可以設為巢狀 nested map
{:c {:a 1, :b 2}}
nested map取值使用的是 get-in,
第一個參數是nested map,後面第二個參數是的要取的那個value的nested keyword[],有一個以上,用vector裝起來
(get-in {:c {:a 1, :b 2}} [:c :a])
=> 1
(get-in {:c {:a 1, :b 2}} [:c :b])
=>  2
舉個context比較有意涵的例子,
假設 error-msg 設定為一個nested-map
;; 表單裡,家用電話error-msg必須是nil(就是必填的意思啦)
(is (= nil (get-in error-msg [:home :phone-no])))
;; 表單裡,手機號碼的國碼error-msg必須是nil(就是必填的意思啦)
(is (= nil (get-in error-msg [:mobile :country-code])))
跟一般map取值不同,
nested map取值,get-in就不能省略不寫了唷~
我們可以使用第二篇文章學過的defn以及keyword api來定義一個可以建立map的function:
(defn creating-map
  [key value]
  {(keyword key) value})
  
tutorial.core=> (creating-map "Taiwan" "Taipei")
{:Taiwan "Taipei"}

然後用def放進變數
tutorial.core=> (def capital (creating-map "Taiwan" "Taipei"))
#'tutorial.core/capital
tutorial.core=> capital
{:Taiwan "Taipei"}
最後來個keywords小提醒~
如果是指定某個namespaced的keywords,需要使用雙冒號 ::
;; 定義新的變數example,用來存放 namespaced的keywords
tutorial.core=> (def example ::ns-example)
#'tutorial.core/example
;; 換成新的namespaced keyword
tutorial.core=> (ns ns-example)
nil
;; namespace已改為ns-example
ns-example=>
;; :tutorial.core/ns-example 這個keyword就是定義好的example變數
ns-example=> (= tutorial.core/example :tutorial.core/ns-example)
true
為了不要離正題Collection太遠,有機會的話之後會再深入聊一下namespace。
明天請繼續收看collection的第四集:Sets!