变量可变性问题

2019-03-02 23:51|来源: 网路

从FP的角度, Clojure中变量是不可变的, 改变一个变量实际是创建一个新的变量

所以所有的change都需要通过参数的不断传递...

如下面的例子,

=> (defrecord Employee [name room])
backtype.storm.util.Employee
=> (def emp (Employee. "John Smith" 304))
#'backtype.storm.util/emp
=> (:name emp)
"John Smith"
=> (assoc emp :room 309)
#backtype.storm.util.Employee{:name "John Smith", :room 309}
=> (println emp)
#backtype.storm.util.Employee{:name John Smith, :room 304}

Clojure是一个妥协的语言,
不单纯的从FP的角度思考, 也需要从OO的角度思考, 你可以认为这是灵活的体现
所以有时候, 单纯的依赖参数的传递很麻烦...虽然很pure FP

希望有变量的可变性, 将结果暂存下来, 这样无疑带来了副作用(side effects), 但提供了些便利, 尤其对习惯于oo思维的工程师

 

两种方法 ,

1. 使用java对象
虽然说clojure变量是不可变的, 但是如果在clojure里面直接使用Java对象, 相当于跳过了clojure这层, 如下面的例子,

=> (import 'java.awt.Point)
java.awt.Point
=> (def pt (Point. 5 10))
#'backtype.storm.util/pt
=> (.x pt)
5
=> (set! (.x pt) -42)
-42
=> (.x pt)
-42 

可以看到在storm里面, 仍然有大量的代码是用java实现的, 尤其是类的封装, 为什么不全用clojure? 可以思考

 

2. 当然clojure并不是没有考虑到这个问题, 他提倡的是管理可变变量

通过ref, atom, 其实是定义reference, 变量本身是不变的, 可以通过swap!将ref或atom切换到不同的变量上

=> (def test-ref (atom {}))
#'backtype.storm.util/test-ref
=> (swap! test-ref assoc :a 1)
{:a 1}
=> @test-ref
{:a 1}

转自:http://www.cnblogs.com/fxjwind/p/3262270

相关问答

更多
  • Python中的元组是一种类似于列表的容器类型,但列表是可变的而元组不可变。 元组本身是不可变的,但是它所包含的元素的可变性取决于该元素的属性。 如:t = (17, 'Jesse', ('LinuxKernel', 'Python'), [17, 'Jesse']) 元组t中的元素数字17和字符串‘Jesse’以及元组('LinuxKernel', 'Python')本身属于不可变元素,故其在元组中不可更新;但是其中包含的列表[17, 'Jesse']本身属于可变元素,故: >>> t = (17, 'J ...
  • 一楼的回答就是“对可变性的封装原则”基本概念,这种东西还是举一个例子吧! 比如“人”作为一个对象来说他是属于可变的,最起码她可以分为男人和女人 ,好了,我们直接上代码 abstract class Person{ //简单的给出了两个属性,姓名和性别 protected String name=""; protected String sex = ""; public Person(String name,String sex){ this.name = name; this.sex = sex; } /* ...
  • 执行并行处理时,问题就会起作用。 前一阵子,我读了Henrik Eichenhardt的博客,回答为什么一个共同的可变状态是万恶的根源。 这是一个简短的推理,为什么共享可变性不好; 从博客中提取。 非确定性=并行处理+可变状态 这个等式基本上意味着并行处理和可变状态组合导致非确定性程序行为 。 如果你只是做了并行处理,并且只有不可变的状态,那么一切都很好,并且很容易推理程序。 另一方面,如果要使用可变数据执行并行处理,则需要将对可变变量的访问进行同步,从而使程序的这些部分单线程化。 这并不是什么新东西,但我 ...
  • 对于数组和字典, let或var关键字决定整个集合是可变的还是不可变的。 换句话说,如果使用let关键字声明字典不可变,则不能更改其任何值,因此第二个示例将不起作用。 在Swift决定集合是可变的还是不可变的只取决于用于声明它的关键字,因此使用let关键字声明数组/字典将等同于声明不可变数组(Objective-C中的NSArray ),同时声明它使用var关键字将为您提供一个可变数组(Objective-C中的NSMutableArray )。 For arrays and dictionaries, t ...
  • 是的,结构的变化状态导致了这种情况。 如果按值传递结构,则在方法中使用它的副本,并且调用代码中的副本不会更改。 Yes, it's the changing state of the structure that causes that. If you pass the structure by value, you would be using a copy of it in the method, and the one in the calling code would not change.
  • 声明一个val并不能保证甚至暗示一个不可变的类型。 它只声明了你可能在Java中调用的最终变量。 该标识符不能被重新分配,但该值可能是可变类型的。 在你的字符串值的例子中,你有一个val和一个不可变类型String。 所以这个标识符既不可重新赋值也不可修改(不可变)。 Declaring a val does not guarantee or even imply an immutable type. It only declares what you might call in Java a final ...
  • on_edit实际上需要一个不可变的回调。 这是否是开发人员的疏忽或有意识的决定并不明显,但是您的代码必须通过使闭包只能不可访问地访问其封闭环境来尊重它。 Rust确实为这种情况提供了逃生舱口: RefCell类型 。 而不是将WordBar移动到闭包中,移动RefCell ,然后使用其borrow_mut()方法可变地借用,将借用检查移动到运行时。 这汇编: fn main() { let mut siv = Cursive::new(); siv.add_global_ ...
  • 可变性是特征中的通用参数吗? 没有。^ _ ^ 以下是关于此事的一些详细讨论( 论坛 , Reddit )。 我认为一般人都认识到目前的状态不理想,但目前也不是非常严格的限制。 关于如何实施以及各种方法的可靠性存在问题。 有些人想知道更高级的类型(HKT)可以解决问题,如果它们被添加到Rust中。 Can mutability be a generic parameter in traits? No. ^_^ Here's some detailed discussion on the matter (In ...
  • WITH A as ( SELECT ambtemp, date_trunc('hour', dt)+ CASE WHEN date_part('minute', dt) >= 6 THEN interval '6 minutes' ELSE interval '0 minutes' END as t FROM temm), B as( ...
  • 在你的第一个例子中, l是一个指针,以及b 。 然后将l附加到b,所以b[0]现在引用指针。 接下来,将4附加到b[0] ,这与l相同,因此将4添加到b[0] 和 l 。 在第二个例子中, ans包含l1的指针,就像b包含l的指针一样 然后,你通过将l1指定给不同的数组来改变l1本身,所以l1改变但是ans[0]没有改变。 从这个最大的问题是append只是改变了列表,并且指针保持不变。 但是,当您将变量设置为不同的列表时,指针会改变。 In your first example, l is a point ...