4.8 KiB
title | localeTitle |
---|---|
Clojure the Basics | Clojure the Basics |
入门
在开始之前,您可能希望安装Clojure和Leiningen (这是一个用于管理Clojure项目的工具)。这将允许您使用REPL(Read-Evaluate-Print-Loop)在命令行中运行Clojure。
定义变量
任何编程语言的面包和黄油都是变量和功能。让我们定义一个变量!
(def our-string "Hello world!")
十分简单。这段代码使用def
宏将字符串( "Hello world!"
)与符号( our-string
)相关联。我们也可以定义一个数字,如1
或1.1
,一个字符,如\a
或\Z
,或更复杂的东西,如列表或正则表达式( uuuugh )。
请注意,我们的代码在括号内,就像列表一样,因为Lisp中的所有内容都是一个列表! (当我们开始讨论宏时,这将非常重要。)
定义功能
现在,让我们定义一个函数!
(defn hello-world [] (println our-string))
这有点复杂。像def
一样,它使用宏( defn
)来创建变量 - 尽管这次,该变量是一个函数。在hello-world
定义该函数的参数之后,空向量(向量是一种列表 - 将其视为数组) - 在这种情况下,我们没有任何参数。之后的代码就是函数的功能。它评估our-string
,它等于"Hello world!"
,并将其打印到控制台。我们来吧!
(hello-world)
; => Hello world!
; nil
你也可以这样写:
(def hello-world (fn [] (println our-string)))
defn
只是帮助您保持代码简洁的捷径。 (defn ...)
和(def ... (fn ...))
在实践中是相同的。
参数
嗯,这很好,但这并不令人兴奋。让我们尝试一个带参数的函数。增加3个号码怎么样?
(defn add [xyz] (+ xyz))
(add 1 2 3)
; => 6
…坚持,稍等。 (+ xyz)
?这看起来很有趣。好吧,Lisps是使用“前缀表示法”编写的,这意味着该函数始终是第一位的。由于Lisp( + - * /
)中的所有数学运算符都只是函数,因此它们也位于它们的参数之前(在本例中为xyz
)。
你会注意到我们的矢量现在有一些东西: [xyz]
!只要函数有参数,就可以在函数名称旁边的向量中定义它们。
解构
关于Clojure中的参数的一个很好的特性是解构。它允许您从列表中“拉出”元素。
(defn add [[xy] z] (+ xyz))
(add [1 2] 3)
; => 6
该函数的参数是集合( [xy]
)和数字( z
)。我们可以使用解构来从列表中拉出第一个和第二个元素,并将它们称为x
和y
。
具有任意数量参数的函数
您还可以使用&
定义具有任意数量参数的函数。
(defn demonstrate-rest [first & rest]
(println first)
(println rest))
(demonstrate-rest 1 "foo" ["bar" 22])
; => 1
; ("foo" ["bar" 22])
; nil
正如您所看到的,使用&
将我们的函数参数分隔为一个名为first
的变量和一个名为rest
的变量列表。这意味着我们的函数可以有任意数量的参数!
返回
您可能已经注意到一些奇怪的事情。每当我们使用println
,似乎nil
出现在我们的输出中。此外,我们的add
函数返回6
,但我们从未告诉它返回任何东西。
在Clojure中,回报是“隐含的”。如果您使用过Ruby,那么您可能对这个概念很熟悉。它不是告诉我们的函数返回某些东西,而是评估其体内的所有代码,并返回结果。例如,我们的add
函数计算(+ xyz)
,然后返回该结果。
我们使用println
输出nil
函数之所以是因为println
计算结果为nil
。 ( nil
就像null
或None
- 它代表什么都没有。)