在百度百科中是这么定义引用类型的:“引用类型 由类型的实际值引用(类似于指针)表示的数据类型。如果为某个变量分配一个引用类型,则该变量将引用(或“指向”)原始值。不创建任何副本。引用类型包括类、接口、委托和装箱值类型”。Clojure的引用类型也于此类似。由于在Clojure中,纯函数式的可谓德高望重,备受推崇,也就意味着要尽量少用或者不用那些具有副作用特性的代码。但对数据状态的更改难以避免,毕竟事物总是变化的,因此Clojure中专门定义了一种引用类型。
以下中英文互译内容参考自Clojure - Functional Programming for the JVM。
Reference types are mutable references to immutable data. There are four
references types in Clojure: Vars, Refs, Atoms and Agents. They have many things in common:
引用类型是非易变数据的可变引用。Clojure中有四种引用类型: Vars, Refs, Atoms 和 Agents。他们具有一些共同点:
<!--[if !supportLists]-->·
<!--[endif]-->They can hold any
kind of object.
他们能够持有任意类型的对象。
<!--[if !supportLists]-->·
<!--[endif]-->They can be
dereferenced to retrieve the object they hold with the deref function or the @ reader
macro.
使用deref函数或者@读取器宏能够间接引用他们以获取他们所持有的对象。
<!--[if !supportLists]-->·
<!--[endif]-->They support
validators which are functions that are invoked when the value changes. If the
new value is valid, they return true. Otherwise they either return false or throw an exception. If they simply return false, an IllegalStateException with the message "Invalid reference
state" will be thrown.
他们都支持使用一种被称作为验证器的函数,这些函数在值发生改变时调用。如果新的值合法则返回true,否则返回false或者抛出异常。当他们简单地返回false时,将会抛出一个带有“Invalid reference state(非法引用状态)”消息的IllegalStateException异常。
<!--[if !supportLists]-->·
<!--[endif]-->They support
watchers which are Agents. When the value of a watched reference changes, the
Agent is notified. For more detail, see the "Agents" section.
他们都支持一种被称作为监视器的Agents。当被监视的引用的值发生改变时,Agent会被告知。更多细节可以参考章节"Agents"。
The table below summarizes some of the differences between the four
reference types and the functions used to create and modify them. Each of the
functions in the table below are described later.
下表总结了四种引用类型的不同的和用于创建并更新他们的函数。表中所列的每一个函数都会在接下来的章节中予以阐述。
|
Var
|
Ref
|
Atom
|
Agent
|
Purpose
|
synchronous changes
to a single, thread-local value
同步更改单个的线程内部的值
|
synchronous, coordinated
changes
to one or more values
同步并且协调地改变一到多个值
|
synchronous changes
to a single value
同步改变单个值
|
asynchronous changes
to a single value
异步改变单个值
|
To create
|
(def name initial-value)
|
(ref initial-value)
|
(atom initial-value)
|
(agent initial-value)
|
To modify
|
(def name new-value)
sets new root value
(alter-var-root (var name) update-fn args)
atomically sets new root value
(set! name new-value)
sets new, thread-local value inside a binding form
|
(ref-set ref new-value)
must be inside a dosync
(alter ref update-fn arguments)
must be inside a dosync
(commute ref update-fn arguments)
must be inside a dosync
|
(reset! atom new-value)
(compare-and-set! atom current-value new-value)
(swap! atom update-fn arguments)
|
(send agent update-fn arguments)
(send-off agent update-fn arguments)
|
Vars
Vars are references that can have a root binding that is shared by all
threads and can have a different value in each thread (thread-local).
Vars引用类型可以拥有供所有线程共享的一个root binding,并且可以在每个线程内部持有一个不同的值。
To create a Var and give it a root binding:
(def name value)
Providing a value is optional. If none is given then the Var is said to be
"unbound". The same form is used to change the root binding of an
existing Var.
值是可选的。如果没有给定值,则Var被当做是为绑定的。可以使用该表达式来改变一个已有Var的root binding,既:(def name value)。
There are two ways to create a thread-local binding for an existing Var:
有两种方式给一个已有Var创建一个线程本地绑定:
(binding [name expression] body)
(set! name expression) ; inside a binding
that bound the same name
Use of the binding macro was described earlier. The following example demonstrates
using it in conjunction with the set! special form. That changes the thread-local value of a Var that was
bound to a thread-local value by the binding macro.
(def v 1)
(defn change-it []
(println "2) v =" v) ; -> 1
(def v 2) ; changes root value
(println "3) v =" v) ; -> 2
(binding [v 3] ; binds a thread-local value
(println "4) v =" v) ; -> 3
(set! v 4) ; changes thread-local value
(println "5) v =" v)) ; -> 4
(println "6) v =" v)) ; thread-local value is gone now -> 2
(println "1) v =" v) ; -> 1
(let [thread (Thread. #(change-it))]
(.start thread)
(.join thread)) ; wait for thread to finish
(println "7) v =" v) ; -> 2
The use of Vars is often frowned upon because changes to their values are
not coordinated across threads. For example, a thread A could use the root
value of a Var and then later discover that another thread B changed that value
before thread A finished executing.
使用var往往是令人皱眉, 因为线程之间对于同一个
______________________________________________________________________________
有待完成
分享到:
相关推荐
重图:clojurescript和clojure的graphql客户
cljs-css-modules:ClojureScript中CSS模块
truss:ClojureScript的断言API
") 并且您应该在浏览器窗口中看到警报。 要清除所有编译文件: lein clean 要创建生产构建运行,请执行以下操作: lein do clean, cljsbuild once min 然后在resources/public/index.html打开浏览器。 您将无法进行...
superlifter:Clojurescript的DataLoader
这将创建一个开发环境,您可以在其中编辑 ClojureScript 代码并立即在浏览器中查看更改,而无需刷新页面。 Lively 不编译 ClojureScript。 (我建议使用 。) Lively 不提供用于处理 JavaScript 文件的 Web ...
Clojure 和 ClojureScript 中的函数式编程介绍LispClojure 基本原理理念/核心原则平台虚拟机JavaScript其他Clojure句法读者REPL特殊表格数据类型原语 细绳 数字 常用表达 收藏 列表 地图 排序图 向量 放 排序集 风俗...
sente:ClojureScript的实时网络通讯
malli:ClojureScript的数据驱动架构
将Clojure代码(和/或AOT编译的类)打包到JAR中 打包一个Uberjar(通过Gradle ) AOT编译 运行clojure.test测试(已集成到Gradle的) 运行nREPL服务器(支持自定义中间件或处理程序) ClojureScript功能 注意: ...
domino:ClojureScript数据流引擎
encore:ClojureScript的核心实用程序库
Ceci 是一个自托管的 ClojureScript 编译器。 它将 Clojure 代码转换为 JavaScript,并最终能够自行编译。 与 : Ceci 有“真正的”宏,定义在普通的源文件中(而不是与代码的其余部分隔离),并且可以通过普通的:...
stater:ClojureScript挂载应用程序的集合
awesome-clojurescript:ClojureScript框架,库和包装器的社区驱动列表
amsterdamjs-clojurescript-workshop:ClojureScript讲习班的教学材料@ AmsterdamJS '18
dispacio:ClojureScript的谓词堆栈分派系统
签出ClojureScript存储库并构建并安装到本地Maven中: cd clojurescript ./script/build 请注意ClojureScript版本号。 修改此仓库的project.clj文件以反映版本号。 从master检出我的分支,并切换到cljs-...
tufte:ClojureScript的简单配置文件和性能监视
删除了Blockly的典型弹出工具栏,直接在Clojure中编程了Blocks。添加自己的工作区右键单击空白以打开解析器。 粘贴以下代码: {:blockpos [[0 0] [0 100] [0 170] [100 170] [0 220]] :code [(:tiles/vert {:title ...