我开始意识到,如果值类型和引用类型都是不可变的,那么它们之间几乎没有什么区别。为了测试这一点,我想看看像Clojure这样真正热爱不可变性的人是如何处理它的。不幸的是,我是一个无知的c#程序员,既不会说Java也不会说Clojure,所以我的谷歌没有帮助。
在c#中,值类型和引用类型是有区别的。这就是经典的"按值传递"one_answers";pass-by-reference"的区别。Clojure中是否存在类似的区别?我确信在Java中是这样的,尽管术语可能不一样。如果它确实存在于Clojure中,它的存在仅仅是因为它直接从Java继承(例如通过导入Java库?)?即使在Java中,这种区别也不存在。有时,通过引用传递对象是很方便的,因为我可以将对象传递给方法,方法可以改变对象,并且我可以在父方法中看到这种变化。但实际上我们只是给方法传递了一个指向对象的指针,value,然后它解引用那个指针来修改它
这可能看起来像是吹毛求疵:隐式指针不是和引用一样吗?不,因为我们调用的方法不能为我们重新分配指针,就像c#可以用ref
参数一样。例如,如果我有一个不可变类型:
final class IntPair {
final int x;
final int y;
IntPair(int x, int y) { this.x = x; this.y = y; }
}
和我传递这样一个IntPair给一个方法,我知道它的x
和y
字段将保持不变。该类型不提供改变自身的方法,该语言也不提供用另一个对象替换该对象的方法。
Clojure继承了所有这些语义。
补充前面的答案:在Java中,"值类型"只是一个常规对象,它是final的,不允许变异。这提供了与Clojure map、vector等相同的语义。这些"不可变对象"由于避免了竞争条件,在多线程领域获得了突出的地位。
背景:Java刚推出时,"市场营销"Java"没有指针",只有"引用",人们对此非常重视。(与C/c++)。孩子们,Java"参考"只是一个指针,不能调用free
或delete
等。请注意,这与使用"按引用传递"的子例程不同。
重申一下,一个"变量"在Java中是指向对象的引用(又名指针)。如果该对象是不可变类的实例,则称为"值对象"。或"值类型"的实例。
注:上面的代码忽略了像long
这样的基本类型。然而,像Long
这样的盒装对象是不可变或"值"的OG。类型。
P.P.S.如果你真的想"通过参考"在Clojure中,目标是允许子例程改变值(例如"5"),然后将值包装在Clojureatom
中,如(atom 5)
,并将传递给对子程序的引用。对atom
的引用是不可变的,但是内容atom
的可以是
(ns tst.demo.core
(:use tupelo.test))
(defn increment-arg
[atom-ref] ; immutable reference to an `atom` holding a value
(swap! atom-ref inc)) ; increment by +1 the contents of the atom
(verify
(let [aref (atom 5)] ; reference to an atom holding the immutable value 5
(increment-arg aref) ; call increment function on the atom reference
(is= 6 (deref aref)) ; extract current value from the atom
))
使用我最喜欢的模板项目构建的示例。
P.P.P.S.您可以在这里找到更多详细信息。