一、环境的配置
1.java环境配置
clojureScript 需要java环境的配置需要下载jdk进行java环境变量配置
下载官网
java环境变量的配置教程
2.Leningen环境配置
1.下载.bat文件内容
2.配置环境变量
2.8.3及以上内容进行配置
lein教程
2.使用vscode
vscode官网
下载插件 Calva:Clojure & ClojureSC
二、数据类型
1. hello world
扩展名.clj
如此便可以在helloWorld.clj中编写第一个clojure程序了!
(ns helloworld) //ns的命令是指命名空间,下载完lein之后创建clj项目便会自带该句(ps)
(+ 1 1) //1+1=,按住ctrl+shift,该句会出现=>2
2.clojure中的数据结构
;; 一、基本数据类型
(type 1.1) ;; clojure.lang.Double
(type 1/3) ;; clojure.lang.Ratio
(type 20) ;;clojure.lang.Long
(type true) ;;clojure.lang.Boolean
(type \c) ;;clojure.lang.Character
(type "hello") ;;clojure.lang.String
(type 'a) ;;clojure.lang.Symbol
(def a 1)
(type #'a)
(type (keyword '0')) ;;clojure.lang.Keyword
;; 二、集合数据类型
2.1 list
(type '(a b c))
(typ (list a b c))
2.2 Vector
(type [1 2 3])
(type (vector 1 2 3))
2.3 Queue
2.4 ArrayMap
(type {:a 1 :b2})
2.5 HashMap
(type (hash-map :a 1 :b 2))
2.6 Set
(type #{:a :b})
三、Clojure中的语句
1.定义一个变量
;; 定义一个symbol的a设置的值为hello,a值不可变
(def a "hello")
;; 定义局部的,直接返回了a
(let [a "hello"]
a)
2.条件语句
if
;; 判断条件
(if (empty? a)
:empty
(do
(prn "not empty ...")
:not-empty))
;;do 某一个距离或者某一个分支有一个副作用返回的是最后一个值,其他的都downlock
单分支
(when-not (empty? a)
(prn "not-empty")
:hahahaha)
case
(case a
"hello" :hi
"good" :nihao
:not-match)
;;与a相等输出后面的值,都不匹配输出not-match
cond
(cond
(= a "hello") :hello
(= (apply str (reverse a) )) "olleh" :resversed-hello)
;;是否等于a,等于hello,都不相等输出else中的值
;;reverse 输出内容有\n需要进行拼接
clojure中,除了nil、false所有都是true
四、定义一个函数
ps:定义之后若要使用该函数名称,需要先执行一遍该定义的内容
;; 3.定义一个函数
;; 函数、后面跟的是一个参数列表,
;;一个函数出现在列表的第一个元素位置的时候会被求值,这样就执行了这个元素
(fn [] "hello world")
;;给函数起一个名字
(def hello (fn [] "hello world"))
;;通常使用 defn 函数名 参数列表 函数体
(defn hello [] "hello world")
1.匿名函数
;; 有一种函数定义了之后只在本地用别处不用
;; #(函数名 函数体 参数(第一个参数就是%1))
#(str "hello" %1)
;; 进行使用,将Kevin作为参数传入
(#(str "hello" %1) "Kevin")
接受三种不同类型的参数,第一个为空,第二个是一个参数、第三个是多个参数(相当于java中的函数重载)
2.函数的解构
;;定义一个函数,接收一个map
;;对此人说hi,name为keyword,keyword可以当函数用
(defn hi [person]
(str "Hi" [:name person]))
(hi {:name "kevin" :title "Major"}) =>"Hi Kevin"
;;解构
(defn hi [{name :name}]
(str "Hi" name))
(hi {:name "kevin" :title "Major"}) =>"Hi Kevin"
3.多参数函数
;; 第一个未带参数,直接返回hello world
;; 第二个 ([name] "hello" name)普通函数中需要return出去变量的内容,此句并没有return,所以要str拼接一下,且换行写
(defn yoho
([] "hello world")
([name]
(str "hello" name)))
(yoho) =>"hello world"
(yoho "Kevin") =>"hello Kevin"
五、clojure中的数据结构
1.list
;;clojure中的数据结构是不可变的,一旦定义之后不可以改变
(def x (list 1 2 3))
;;向里面增加一个新元素
(cons 0 x) =>(0 1 2 3)
;;原始x中的内容
x => (1 2 3)
;;有顺序的取值
(first x) =>1
(last x) =>3
;;nth取任意元素
(nth x 0)=>1
;;最高效的把一个元素加入到数据结构,在list链表中插入头部的效率最高
(conj x 0) =>(0 1 2 3)
2.Vector
;;clojure中的数据结构是不可变的,一旦定义之后不可以改变
(def x [1 2 3])
;;向里面增加一个新元素
(cons 0 x) =>(0 1 2 3)
;;原始x中的内容
x => (1 2 3)
;;有顺序的取值
(first x) =>1
(last x) =>3
;;nth取任意元素
(nth x 0)=>1
;;注意conj在该数据结构中与在list中不同
(conj x 0)=>[1 2 3 0]
3.map
;;定义一个map
(def m ({:a 1 :b 2}))
;;建立连写
(assoc m :c 3)=>{:a 1 :b 2 :c 3}
;;对于 m来说它的值仍然是{:a 1 :b 2}
;;assoc-in a的结构是一个嵌套结构,要修改a中b的值为10
(assoc-in {:a {:b 1}} [:a :b] 10)
;; 在a中新增一个元素c
(assoc-in {:a {:b 1}} [:a :c] 10) =>{:a {:b 1 :c 10}}
;;update-in 也是用来更新map中的数据
;; inc函数,b原来指向的函数+1,得到b = 2
(update-in {:a {:b 1}} [:a :b] inc) =>{:a {:b 2}}
;;要获得map中的值,可以用keyword直接获得,m中的a值=1
(:a m)
;;等价于使用get中map的值
(get m :a)
对于map常见的几种类型
;; hash
(hash-map :a 1)
;;array
(array-map :b 2)
;;map本身的key-value是没有顺序的,如果非要有顺序可以使用sorted-map
(sorted-map :a 1 :b 2)
4.Set
;;定义一个set的数据结构
(def s #{1 2 3})
;;使用conj为set添加一个新值
;;注意set是无序的不一定会添加到哪里
(conj s 4)
;;使用contains判断set中是否含有某个值
(contains? s 9)
六、递归和高阶函数
1.递归函数
;; 定义一个sum'函数,接收一个total作为临时变量,接收一个数组vals
;;递归实际上就是数组为空,数组为空了就返回一个值total
;;当前数组不为空的时候就继续调用自己,sum'的值就是加上数组中的第一个值,拿掉加过的值
(defn sum' [total vals]
(if (empty? vals)
total
(sum' (+ first vals)
(rest vals))))
(sum' 0 [1 2 3 4])=>10
;;上述方法有一个total临时变量不太好
;;改为多参数的,第一个vals,希望调用有两个参数的sum'
;;定义两个参数的函数
(defn sum'
([vals] (sum' 0 vals))
([total vals]
(if (empty? vals)
total
(sum' (+ first vals)
(rest vals)))))
(sum' [1 2 3 4])
递归优化
;;jvm限制,本地优化,必须给编译器或者显示器一些提示,不能使用函数名直接调用,使用recur
(defn sum'
([vals] (sum' 0 vals))
([total vals]
(if (empty? vals)
total
(recur (+ first vals)
(rest vals)))))
(sum' [1 2 3 4])
定义sum函数,单参是需要的,多参是不需要的,递归点不一定是函数名,可以loop,只要loop开始就绑定做一个递归点
(defn sum'
[vals]
(loop [total 0
vals vals]
if (empty? vals)
total
(recur (+ total (first vals))
(rest vals))))
(sum' (range 1000))
reduce
;; reduce接受三个参数,第一个接受一个函数,第二个接收一个初始值,第三个接收要处理的参数
(reduce (fn my-add [total val]
(+ total val)) 0 [1 2 3 4])
;;将my-add函数拿出来
(defn my-add [total val]
(+ total val))
(reduce my-add 0 [1 2 3 4])
;;可以将初始值省略
(reduce my-add [1 2 3 4])
;;等价于reduce中的加法
(reduce + [1 2 3 4])
2.高阶函数
reduce 是高阶函数中最普适的一个
;;过滤 是否是偶数
;;传递的是两个值,一直累计的结果,中间传入的value
;;先判断传入的值是否是偶数,如果是偶数acc就添加,如果不是就把acc返回
(defn filter-even [acc,val]
if(even? val) (conj acc val) acc)
(reduce filter-even [] [1 2 3 4]) =>[2 4]
;;或者直接使用clojure函数
(filter even? [1 2 3 4])=>[2 4]
;;数组中的每个值加1
(defn map-inc [acc val]
(conj acc (inc val)))
;; 返回数组的需要指定初始值
(reduce map-inc [] [1 2 3 4])
;;等价于
(map inc [1 2 3 4])
;;偶数和奇数分为两组
(defn group' [acc val]
(if (even? val)
(update-in acc [:even] #(conj % val))
(update-in acc [:odd] #(conj % val))))
(reduce group' {} [1 2 3 4])=>{:odd (3 1), :even (4 2)}
;;相当于
(group-by (fn [val] (if (even? val) :even :odd))
[1 2 3 4])
七、使用lein创建项目
在命令行中创建项目,注意项目名称大小写的问题
lein new learnclj
目录:
目录 | 内容 |
---|---|
product.clj | 配置文件 dependencies:依赖 |
src/learnclj/core.clj | 文件主要内容 |
使用lein进行启动
启动之后,直接进行调用
添加main函数,执行lein run
main函数前面加-,指的是静态函数
lein run -m learnclj.core
可以在配置函数中添加
直接使用命令
lein run
产生同样效果
也可以编译成jar包,
在core.clj页面添加
使用命令
lein uberjar
target目录下有两个jar包
再执行
java -jar target/learnclj-0.1.0-SNAPSHOT-standalone.jar
同样可以出现如下效果
八、如何在clojure中引入一个库