clojure 安装使用
安装过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| lein self-install
lein new app myclojure
lein compile myclojure.core
lein run myclojure.core
lein run -m myclojure.demo/say
|
clojure 编译
在一个命名空间中的函数将编译成该命令空间下的内部类。
函数将继承自 clojure.lang.RestFn 类, 并 override 一个对应参数个数的 invoke 方法。
例如:
1 2 3 4
| (defn -main "I don't do a whole lot ... yet." [& args] (println "Hello, World!"))
|
函数 -main 接受一个 序列 作为参数,所以编译后的代码中重写
1 2 3 4
| protected Object doInvoke(Object args) { return null; }
|
一般还会生成一个 invokeStatic 方法,这个方法包涵 函数 的核心实现逻辑。 doInvoke 将参数准备好之后,就直接调用这个方法。
如果在函数在的实现中使用的其它函数,则会有一个 clojure.lang.Var 类型的变量来引用这个函数对象。例如上面的 -main 函数中使用了 函数 clojure.core/println 进行输出操作。
则,函数编译后的类中,将会一个对应的 Var字段, 代表这个函数的引用, 其初始化的方法,如下:
1 2 3 4 5 6
|
Var var = RT.var("clojure.core", "println");
|
1 2 3 4 5 6 7
| (defn println "Same as print followed by (newline)" {:added "1.0" :static true} [& more] (binding [*print-readably* nil] (apply prn more)))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| ;; init ;; 在 init 函数中初始化 const__1303 ldc_w "clojure.core" ldc_w "println" invokestatic clojure/lang/RT/var(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Var; checkcast clojure/lang/Var putstatic clojure/core__init/const__1303 Lclojure/lang/Var; ;; 上面的字节码片断相当于下面的代码 ;; var 方法创建命令空间 "clojure.core", ;; 并创建一个 var 对象。将其放置到命名空间中,然后返回 Var const__1303 = clojure.lang.RT.var("clojure.core", "println");
;; const__1306 的初始化 invokestatic clojure/lang/RT/map([Ljava/lang/Object;)Lclojure/lang/IPersistentMap; checkcast clojure/lang/AFn putstatic clojure/core__init/const__1306 Lclojure/lang/AFn; ;; 上面的字节码片断相当于下面的代码 ;; 其中对象数组中存储着 clojure.core/println 函数的元信息 ;; 例如 {:added "1.0" ;; :static true} ;; RT.map 方法返回一个 PersistentArrayMap 对象 ;; 这个对象继承自 AFn AFn const__1306 = clojure.lang.RT.map(new Object{//....});
;; core__init.class/load
;; const__1303 (Var)指向 clojure/core$println 对象。 getstatic clojure/core__init/const__1303 Lclojure/lang/Var; dup
;; const__1306 指向 getstatic clojure/core__init/const__1306 Lclojure/lang/AFn; checkcast clojure/lang/IPersistentMap invokevirtual clojure/lang/Var/setMeta(Lclojure/lang/IPersistentMap;)V dup
;; 创建类 clojure/core$println 的对象。 new clojure/core$println dup invokespecial clojure/core$println/<init>()V ;; 调用上面 const__1303 这个 Var 的 bindRoot 方法。 ;; 将创建好的 clojure/core$println 对象设置为其 root 对象。 invokevirtual clojure/lang/Var/bindRoot(Ljava/lang/Object;)V
;; 上面的字节码片断相当于下面的代码 Var const__1303; AFn const__1306; const__1303.setMeta(const__1306); const__1303.bindRoot(new clojure.core$println());
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| ;; clojure.core__init.class/__init13 方法。 ;; const__1303 的创建 ;; !!! clojure/lang/RT/var 这个方法调用最终将 !!! ;; !!! 创建一个 "clojure.core" 的命令空间 ;; !!! 并将 "println" 注册到这个命令空间中 ;; 此后, Namespace.mappings 对象中 将有一个 ;; key为 "println" 的对象。 ;; 同时创建的每一个命令空间将被放置到 Namespace.namespaces ;; 这个静态字段中,并且其 key 为 "clojure.core" ldc_w "clojure.core" ldc_w "println" invokestatic clojure/lang/RT/var(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Var; checkcast clojure/lang/Var putstatic clojure/core__init/const__1303 Lclojure/lang/Var;
;; const__1306 的创建 bipush 14 anewarray java/lang/Object dup iconst_0 aconst_null ldc_w "arglists" invokestatic clojure/lang/RT/keyword(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Keyword; aastore dup iconst_1 iconst_1 anewarray java/lang/Object dup iconst_0 aconst_null ldc_w "&" invokestatic clojure/lang/Symbol/intern(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Symbol; aconst_null ldc_w "more" invokestatic clojure/lang/Symbol/intern(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Symbol; invokestatic clojure/lang/Tuple/create(Ljava/lang/Object;Ljava/lang/Object;)Lclojure/lang/IPersistentVector; aastore invokestatic java/util/Arrays/asList([Ljava/lang/Object;)Ljava/util/List; invokestatic clojure/lang/PersistentList/create(Ljava/util/List;)Lclojure/lang/IPersistentList; aastore dup iconst_2 aconst_null ldc_w "doc" invokestatic clojure/lang/RT/keyword(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Keyword; aastore dup iconst_3 ldc_w "Same as print followed by (newline)" aastore dup iconst_4 aconst_null ldc_w "added" invokestatic clojure/lang/RT/keyword(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Keyword; aastore dup iconst_5 ldc_w "1.0" aastore dup bipush 6 aconst_null ldc_w "static" invokestatic clojure/lang/RT/keyword(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Keyword; aastore dup bipush 7 getstatic java/lang/Boolean/TRUE Ljava/lang/Boolean; aastore dup bipush 8 aconst_null ldc_w "line" invokestatic clojure/lang/RT/keyword(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Keyword; aastore dup bipush 9 sipush 3631 invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer; aastore dup bipush 10 aconst_null ldc_w "column" invokestatic clojure/lang/RT/keyword(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Keyword; aastore dup bipush 11 iconst_1 invokestatic java/lang/Integer/valueOf(I)Ljava/lang/Integer; aastore dup bipush 12 aconst_null ldc_w "file" invokestatic clojure/lang/RT/keyword(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Keyword; aastore dup bipush 13 ldc_w "clojure/core.clj" aastore invokestatic clojure/lang/RT/map([Ljava/lang/Object;)Lclojure/lang/IPersistentMap; checkcast clojure/lang/AFn putstatic clojure/core__init/const__1306 Lclojure/lang/AFn;
|
1 2 3 4 5 6 7 8 9 10 11 12
| ;; const__1303 和 const__1306 初始化 ;; load 函数。 getstatic clojure/core__init/const__1303 Lclojure/lang/Var; dup getstatic clojure/core__init/const__1306 Lclojure/lang/AFn; checkcast clojure/lang/IPersistentMap invokevirtual clojure/lang/Var/setMeta(Lclojure/lang/IPersistentMap;)V dup new clojure/core$println dup invokespecial clojure/core$println/<init>()V invokevirtual clojure/lang/Var/bindRoot(Ljava/lang/Object;)V
|
所以 core__init.class 的主要作用就是创建函数对象的实例。
clojure 运行时的准备
clojure 运行时环境的准备由 clojure.lang.RT 类来完成,这个类会首先创建一个默认的命名空间 “clojure.core”
1
| static public final Namespace CLOJURE_NS = Namespace.findOrCreate(Symbol.intern("clojure.core"));
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
final static ConcurrentHashMap<Symbol, Namespace> namespaces = new ConcurrentHashMap<Symbol, Namespace>();
transient final AtomicReference<IPersistentMap> mappings = new AtomicReference<IPersistentMap>();
|
变量
局部变量
1 2 3 4 5
|
(defn defvar [] (let [a 123] (println a)))
|
上面的函数相当于下面的 java 代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| void defvar(){
{ int a = 123; System.out.println(a); }
System.out.println(a); }
|
全局变量
而使用 (def a), 则是在当前的命名空间中创建了一个 Var 变量。从而这个方法可以通过 命名空间+变量名称的 方式被任何一个函数使用。
通过(def) 语句定义的变量相当于类的字段。
命名空间的 __init.class 类,会把这个 Var 对象注册到当前命名空间中。
当前命名空间和其它命名空间中的函数都可以通过 命名空间+变量名 的方法访问该变量。
修改全局变量,仍然使用 (def) 语句
(def x new_value)
这个语句将调用 Var 变量 x 的 bindRoot 方法将新值绑定到 x.
线程绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| (def ^:dynamic x)
(defn defvar [] (binding [x (java.util.Date.)] (binding [x "hello binding."] (println x)) (println x)) (println x))
|
实现线程绑定的核心是 clojure.lang.Var.pushThreadBindings 和 clojure.lang.Var.popThreadBindings
Ref 加锁的引用
使用 (def x (ref 123)) 创建一个 clojure.lang.Ref.Ref 对象
每一个 ref 对象都有一个锁,对其进行操作时会默认进行加锁。
使用 @x 可以获得变量的值,
1 2 3
| (defn defvar [] (def x (ref 890)) (println @x x))
|
Atom 变量
1 2 3
| (def my-atom (atom 1)) (reset! my-atom 2) (println @my-atom)
|
atom 是 java.util.concurrent.atomic.AtomicReference 的包装,便于在 clojure 中使用
Agent
$. 参考
- clojure docs
- clojure
- clojure.github
- leiningen
- clojure-doc