一、标准的流程控制







if:




将一个判断表达式作为它的第一个参数进行求值。如果求值为true,那么就返回它的第二个参数(相当于“then”子句)的求值结果。如果结果为false(包括nil)就返回第三个参数的求值结果(相当于“else”子句),前提是有提供第三个参数并且不为空。


  1. user=> (defn is-small [number] (

    if

    (< number

    100

    )

    "yes"


    "no"

    ))

  2. #'user/is-small

  3. user=> (is-small

    50

    )


  4. "yes"


  5. user=> (is-small

    110

    )


  6. "no"




if条件中除了false和nil,其他都为true:


  1. user=> (

    if


    true


    "true"

    )


  2. "true"


  3. user=> (

    if


    0


    "true"

    )


  4. "true"


  5. user=> (

    if


    ""


    "true"

    )


  6. "true"


  7. user=> (

    if

    nil

    "true"

    )

  8. nil

  9. user=> (

    if


    false


    "true"

    )

  10. nil




if-not:




跟 if 的用法相同,但是作用是相反的。当逻辑为false的时候会去计算第二个参数的值,为true的时候才计算第三个参数的值


  1. user=> (

    if

    -not (zero?

    0

    )

    "no"


    "yes"

    )


  2. "yes"


  3. user=> (

    if

    (not (zero?

    0

    ))

    "no"


    "yes"

    )


  4. "yes"




if-let:




if-let宏接受两个参数,第一个参数为绑定变量,第二个参数为表达式。并根据第二个表达式参数返回的值确定执行then、else语句。


  1. user=> (defn

    if

    -let-test [arg] (

    if

    -let [x arg]

    "true"


    "false"

    ))

  2. #'user/

    if

    -let-test

  3. user=> (

    if

    -let-test

    1

    )


  4. "true"


  5. user=> (

    if

    -let-test nil)


  6. "false"


  7. user=> (

    if

    -let-test

    false

    )


  8. "false"




when:




when没有else子句,如果when后面第一个参数为true,则执行条件后的所有语句,否则返回nil。


  1. user=> (when

    false

    (println

    "is true"

    )

    "return true"

    )

  2. nil

  3. user=> (when

    true

    (println

    "is true"

    )

    "return true"

    )

  4. is

    true



  5. "return true"


  6. user=> (def has-value (when

    true

    (println

    "hello world"

    )

    "returned value"

    ))

  7. hello world

  8. #'user/has-value

  9. user=> has-value


  10. "returned value"




when-not:




when-not与when类似,只是第一个参数返回false,才执行后面所有语句,否则返回nil。


  1. user=> (when-not

    false

    (println

    "is true"

    )

    "return true"

    )

  2. is

    true



  3. "return true"


  4. user=> (when-not

    true

    (println

    "is true"

    )

    "return true"

    )

  5. nil




when-let:




when-let与if-let类似,只有绑定变量值不是false、nil时,才执行后面所有语句,否则直接返回nil。


  1. user=> (when-let [a

    true

    ] (println

    "true"

    )

    "return true"

    )


  2. true



  3. "return true"


  4. user=> (when-let [a

    false

    ] (println

    "true"

    ))

  5. nil

  6. user=> (when-let [a nil] (println

    "true"

    ))

  7. nil




cond:




cond 可以有任意个“判断/表达式”对,作为它的参数。如果满足第一个判断,就执行第一个判断对应的表达式。如果没有满足第一个条件,就会尝试后面的判断表达式,以此类推。如果一个都没有满足,那么返回 nil 除非你用一个 :else 关键字放在最后来抓住剩下的所有可能性。cond类似于java中的switch..case..default语句,如:


  1. user=> (defn f [n] (cond (< n

    0

    )

    "<0"

    (< n

    10

    )

    "<10"

    :

    else


    ">=10"

    ))

  2. #'user/f

  3. user=> (f -

    2

    )


  4. "<0"


  5. user=> (f

    2

    )


  6. "<10"


  7. user=> (f

    10

    )


  8. ">=10"




case:




case可以简单理解为java中switch的case,如下


  1. user=> (let [mystr

    "hello"

    ];首先绑定mystr的值为hello

  2. (

    case

    mystr


  3. ""


    0



  4. "hello"

    (count mystr)));

    case

    用于匹配mystr的值


  5. 5


  6. user=> (let [mystr

    "no match"

    ]

  7. (

    case

    mystr


  8. ""


    0



  9. "hello"

    (count mystr)


  10. "default"

    )) ;最后一个表达式只有匹配不成功时才执行


  11. "default"




case可以用列表一次匹配多个值:


  1. user=> (defn f [x] (

    case

    x

  2. (

    5


    10

    )

    "*5"


  3. (

    3


    6


    9

    )

    "*3"



  4. "others"

    ))

  5. #'user/f

  6. user=> (f

    5

    )


  7. "*5"


  8. user=> (f

    10

    )


  9. "*5"


  10. user=> (f

    6

    )


  11. "*3"


  12. user=> (f

    1

    )


  13. "others"




do:




do执行多条语句,返回最后一条语句值


  1. user=> (def v (

    do

    (println

    123

    ) (println

    321

    ) -

    1

    ))


  2. 123



  3. 321


  4. #'user/v

  5. user=> v

  6. -

    1




loop、recur:




如果递归的层次太深的话,那么可能会产生内存不足的情况。所以一些编程语言利用 “tail call optimization” (TCO)的技术来解决这个问题。在Clojure里面避免这个问题的一个办法是使用loop 和recur。


  1. ;定义递归语句完成

    10

    +

    9

    +……

    1

    =

    55


  2. user=> (loop [sum

    0

    cnt

    10

    ] (

    if

    (= cnt

    0

    ) sum (recur (+ cnt sum) (dec cnt))))


  3. 55




loop/recur 组合把一个看似递归的调用变成一个迭代 — 迭代不需要占用栈空间。 loop special form 跟let special form 类似的地方是它们都会建立一个本地binding,但是同时它也建立一个递归点, 而这个递归点就是recur的参数里面的那个函数。loop给这些binding一个初始值。对recur 的调用使得程序的控制权返回给loop 并且给那些本地binding赋了新的值。给recur传递的参数一定要和loop所创建的binding的个数一样。同样recur只能出现在loop这个special form的最后一行