前几章中,咱们用了一种比较迂回的方式建立函数:把匿名函数绑定到一个变量上。实际上,clojure提供了一个更好的方式作同一件事情。“defn” 这个函数就是专门用于定义函数的。 java
在咱们使用defn以前,咱们再回顾一下以前咱们怎么使用def来建立函数的,而后咱们使用defn来作同一件事情对比一下。 shell
;;使用def =>(def alphabet-length (fn [ ](count alphabet))) #'user/alphabet-length =>(alphabet-length) 26 ;;使用defn =>(defn alphabet-length [ ](count alphabet)) #'user/alphabet-length =>(alphabet-length) 26上面两种方式作的都是同一件事情。可是defn能作更多的事情。下面是defn定义函数的一个脚手架:
[1] (defn name 函数名 [2] "description" 函数描述 (可选) [3] {metadata} 元数据 (可选) [4] [arguments] 参数列表 [5] body-of-expressions...) 函数体上面咱们能够看出,defn在定义函数时能够提供更多的信息。
下面让咱们用上面这些信息定义一个函数: express
=>(defn select-random "从一个列表中随机返回一个元素" {:added "1.2"} ;; 元数据 [options] (nth options (rand-int (count options)))) #'user/select-random
(count options) 用于计算options包含的元素数量。(nth options x) 用于从options中获取第x个元素(从0开始,相似java中的list的get方法) 编程
咱们以前说过clojure是lisp的一种方言。lisp 是 “List Processor”的缩写,就是列表解析的意思,使用列表来表示全部的东西(S表达式)。从咱们写的代码也能够看出,整个代码结构就是一个嵌套的列表。如今让咱们用列表结构来保存数据: app
=>(list "growl" "lick" "jump") ("growl" "lick" "jump")咱们以前定义的函数select-random须要的参数正是一个列表,正好咱们就能够用来测试:
=>(select-random (list "growl" "lick" "jump")) "jump" =>(select-random (list "growl" "lick" "jump")) "growl"运行一切正常,说明select-random没什么问题。咱们能够在一个新的函数中来使用它。咱们来建立一个用于问候的函数greeting。
=>(defn greeting "Composes a greeting sentence. Expects both the name of a greeter and the name of whom is to be greeted for arguments. An approach and an action are randomly selected." {:added "1.2"} [greeter whom] ;;str 用于组装字符串 (str greeter " greeted " whom " with a " (select-random (list "ferocious" "wimpy" "precarious" "subtle")) " " (select-random (list "growl" "lick" "jump")) "!")) #'user/greeting =>(greeting "Jon" "Thaddeus") "Jon greeted Thaddeus with a wimpy growl!" =>(greeting "Jon" "Thaddeus") "Jon greeted Thaddeus with a precarious lick!"
固然,上面的问候函数不是很完美。咱们能够把问候语句单独提出来。 dom
=>(def approaches (list "ferocious" "wimpy" "precarious" "subtle")) 'user/approaches =>(def actions (list "growl" "lick" "jump")) #'user/actions而后在greeting中使用绑定的列表:
=>(defn greeting "Composes a greeting sentence. Expects both the name of a greeter and the name of whom is to be greeted for arguments. An approach and an action are randomly selected." {:added "1.2"} [greeter whom] (str greeter " greeted " whom " with a " (select-random approaches) " " (select-random actions) "!")) #'user/greeting如今可读性好多了吧,把变化的部分单独抽象出来这个原则对于函数式编程也是通用的哦。这样咱们就能够在不修改函数的状况下改变问候语句了。
至于函数定义中的元数据有什么做用,暂时保密,后面会单独来说。 函数式编程