【clojure】入门篇-01

一、环境的配置

1.java环境配置

clojureScript 需要java环境的配置需要下载jdk进行java环境变量配置

下载官网

java环境变量的配置教程

2.Leningen环境配置

1.下载.bat文件内容

2.配置环境变量

2.8.3及以上内容进行配置

lein教程

2.使用vscode

vscode官网

下载插件 Calva:Clojure & ClojureSC

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ynkUFwZg-1692547087648)(C:\Users\24955\AppData\Roaming\Typora\typora-user-images\image-20230809085620838.png)]

二、数据类型

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中引入一个库

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/liqiannan8023/article/details/132398256