Clojure极简教程
发布日期:2021-10-06 15:05:16 浏览次数:12 分类:技术文章

本文共 4122 字,大约阅读时间需要 13 分钟。

文章目录

简介与安装

是Lisp在JVM中运行的一种方言,所以可以预想其语言风格是括号之间的环环相扣。由于是在Java虚拟机中运行,所以应该事先下载,然后安装Clojure。

在windows下有两种安装方法,其一是通过mvn对源码进行编译,

git clone https://github.com/clojure/clojure.gitcd clojuremvn -Plocal -Dmaven.test.skip=true package

其二是通过安装Clojure管理程序,可无痛安装。

通过Lein命令lein repl可以进入交互式窗口,可以快速验证一些较为简单的方法,有利于快速学习Clojure。
在这里插入图片描述

初步使用

运算符

若从未接触过Lisp,Clojure的语法可能显得比较吊诡,这里将运算符函数化了,即在Clojure中,如果想表达1+1,则相当于调用Add(1,1),从而保证所有功能皆可通过类似的语法来实现。这样也有一些好处,即在某些场合其实更加简洁:

user=> (+ 1 2)3user=> (+ 1 2 3 4 5)15user=> (+ 1,2,3)6user=> (* 1,2,4,)8user=> (> 1,2)falseuser=> (/ 2,4)1/2

此外这样也能避免由于优先级可能引发的错误。

运算符 功能 备注
+ - * / rem 加减乘除、求余
inc 操作数+1 (inc 1)相当于1++
dec 操作数-1
max min 最大值 最小值
=、not=、>、>=、<、<= 顾名思义
and or not 与或非
bit-and bit-or bit-not 按位与或非
bit-xor 按位亦或

需要注意,inc和dec只能传入一个参数,其他运算符则不然,当输入参数大于2时,相当于在每个变量之间均插入一个运算符,即(+ a b c) → \to a+b+c

在命令行中,运算符*还有一个特殊的含义,它可以引用我们此前输出结果。

user=> (+ 3 4)7user=> *17user=> (* 4 5)20user=> (+ *1 *2)27

变量与数据类型

变量声明相当于把一个值赋予一个符号,本质上也是值与符号的函数,这个函数即def。Clojure中的基元类型都是从Java中继承而来,所以支持整形浮点型布尔型等相关类型,并且无需声明即可调用。需要注意的是,其字符串需要用双引号进行标识。

除此之外,Clojure还支持四种集合类型,即list、vector、set、map。

user=> (def str "hello");字符串,clojure中用;进行注释user=> (println str)helloniluser=> (def testList '(1 2 3));listuser=> (def testVec [1 2 3]);vectoruser=> (def testSet #{
1 2 3});setuser=> (def testMap {
:a 1, :b 2});map

需要注意,list的小括号前面需要加上一个单引号,否则会被识别成一个表达式从而报错。此外,如果新建一个不想其赋值的变量,也可以用单引号来延迟赋值。

user=> 'xx

函数

Clojure中,函数通过关键字defn来定义,格式为(defn 函数名 [args] (),调用格式为(函数名 args)

user=> (defn test [x] (+ x 2))#'user/testuser=> (test 5)7

控制结构

循环

类型 语法 示例 说明
while循环 (while () (do ()) (while (< x 5) (do (def x (inc x)))) 当x<5时x++
doseq (doseq [] ()) (doseq [x testList] (println x)) 打印testList
dotimes (dotimes [] ()) (dotimes [n 5] (def x (inc x)) x=x+5,将后面的语句执行5次

实例代码

user=> (def x 1)user=> (while (< x 5) (do (def x (inc x))))user=> x5user=> (def testList '(1 2 3))user=> (doseq [n testList] (println n))123niluser=> (dotimes [n 5] (def x (inc x)))user=> x10

判断

类型 语法 示例 说明
if (if () () ()) (if(> a b) (println a) (println b)) 输出ab的最大值
if do if () (do ()) (do ()) (if (> a b) (do (println a) (println True)) do()) do内可以执行多种操作
case (case x a () b () c() …) (case x a (println “a”) b (println “b”) c(println “c”) …) 如果是a则打印“a”…
cond (cond (cond1)(code1) (cond2)(code2)) (cond (> x 1)(println">")(< x 1)(println"<") 如果x>1,则输出">"…

示例代码:

user=> (def a 2)user=> (def b 4)user=> (if(> a b) (println a) (println b))4user=> (if (> a b) (do()()) (do (println b) (println true)))4trueuser=> (case a 1 (println "1") 2 (println "2"))2user=> (cond (> a b) (println "a") (< a b) (println "b"))b

需要注意一点,在coljure中,除了nil和false之外,所有值转化为布尔型均为true。

递归

从形式上来说,递归只是循环的一种特殊形式,区别在于递归需要调用函数体自身。但从运行的角度来说,如果遍历某一个数组testList,可以使用语句(doseq [x testList] (println x)),当x为testList第i个元素时,可以断定第i-1之前的所有状态都将毫无意义。但是递归语句则不然,在调用函数自身的过程中,需要将此前的所有状态压入栈中,这也是斐波那契数列爆内存的缘由。

可能是基于这个原因,一些函数式语言都将递归进行了特殊的声明,例如F#中需要用到关键字rec
在Clojure中,通过关键字recur实现递归操作,可以分别嵌入到loop循环和函数中。其中,Clojure中通过关键字defn来绑定一个函数

user=> (loop [i 0] (when (< i 5) (println i) (recur (+ i 2))))024nil;Clojure中通过defn来绑定一个函数user=> (defn print2 [i] (if (< i 5) (do (println i) (recur (+ i 2)))))#'user/print2user=> (print2 0)024niluser=> (defn fact [x] (loop [n x f 1] (if (= n 1) f (recur (dec n) (* f n)))));定义递归函数#'user/factuser=> (fact 15)1307674368000user=> (loop [n 15 f 1] (if (= n 1) f (recur (dec n) (* f n))))1307674368000

上面代码中,loop循环的含义为,n的初始值为15,f的初始值为1。如果n==1,则输出f,否则将n-1赋值给n,将f*n赋值给f。

异常

异常本质上来说也是一种判断,或者说异常是一个布尔值。

类型 语法 示例 说明
assert (assert ()) (assert false) 当表达式为false时抛出异常
try throw finally (try (throw ())(finally ())) 抛出这个throw块的异常并执行finally中语句
try catch finally (try ()(catch ())(finally ())) 如果发生异常,则执行catch中语句,否则执行finally中语句
try throw catch

函数

此前稍微提到了一点函数,但并不足以体现出函数式语言的强大。

重载

Clojure中,通过增加函数体来实现类似重载的功能,其格式为

(defn 函数名 	([args1] ()) 	([args2] ())	...)

例如

user=> (defn test ([] (println "empty")) ([a] (println a)))user=> (test)emptyuser=> (test 1)1

参数可变函数

Clojure中通过关键字&实现对输入参数可变的函数。例如

user=> (defn prints [ & num ] (println num))user=> (prints 1 2 3 4 5)(1 2 3 4 5)

匿名函数

Clojure通过关键字fn定义匿名函数。其格式为((fn [形参] (函数体)) 实参)

user=> ((fn [test] (println test)) "a")anil

有了匿名函数,意味着可以直接把函数体写在主程序里,也就是说无论什么Clojure代码都可以写成一行。

转载地址:https://blog.csdn.net/m0_37816922/article/details/100175523 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Groovy极简入门
下一篇:Docker的maven插件

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月05日 16时32分43秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

年度总结 | 2020CSDN的第一桶金 2019-04-28
IT 圈都在聊的10大技术热点 2019-04-28
研发与运维一体化,见证终极协同奥义 2019-04-28
微软 Power Apps 让人人都能开发小程序 2019-04-28
大咖圆桌会【Azure AI的落地实践】 2019-04-28
微软 Power Platform 在中国市场正式商用 无缝衔接微软智能云“三驾马车” 2019-04-28
做项目很累?那是你的“姿势”不对! 2019-04-28
零差评“独角戏”,技术族一集入坑 2019-04-28
先行者说 |“芯”痛之下,半导体企业如何破局? 2019-04-28
“转型·云之道”微视频开播!No.1 - 谁是云时代游戏规则改变者? 2019-04-28
“转型云之道”微视频第二期,Linux or 容器?两者皆真爱! 2019-04-28
微软爱开发者 |燥热预警!收下这份物联网 IoT “清凉秘籍” 2019-04-28
游戏行业被 DDoS “围攻”,微软带它来“解救” 2019-04-28
喜大普奔,Azure AD B2C 落地中国,即刻开启企业级身份验证方案! 2019-04-28
Azure 安全网络篇 - DMZ 区域设计实践 2019-04-28
快速、经济、可靠的TB 级数据传输方案:Azure Data Box 磁盘服务 2019-04-28
在 Azure SQL 上优化成本的八种方法 : 成本节省高达80% ! 2019-04-28
《数据“科学家”必读》 | 从零起步打造数字化业务「最强大脑」 2019-04-28
好消息!Azure Active Directory 域服务在中国区正式发布! 2019-04-28
《数据“科学家”必读》 | 与Cosmos DB实现数据同步 2019-04-28