【发布时间】:2023-03-31 05:35:01
【问题描述】:
这个问题是在学习一些关于 Scala 的教程时想到的,但我认为在函数式编程方面总的来说很有趣。
我不确定 FP 中不变性的重要性。我可以想到两种不同的情况:
1) 类方法不返回实际字段,而是返回它们的副本。例如,如果我们有一个 Dog 类我们需要保持不可变,那么它的功能:
getToys() { return new ArrayList(this.toys); }
代替:
getToys() { return this.toys; }
这种情况对我来说很有意义,在第二种情况下,客户端代码实际上可能会损坏对象。我的怀疑在于第二种情况:
2) 在 Scala 和大多数其他 FP 语言中,我们更喜欢递归调用:
sum(x: List[Int], acc: Int) {
if(x.isEmpty) return acc;
sum(x.tail, acc + x.head);
}
反对传统的 for 循环递增累加器。原因是这个累加器是一个可变变量。
这个变量永远不会暴露在函数之外,那么为什么要让它不可变呢?
编辑:
似乎最重要的最佳实践是引用透明度 而不是严格的不变性,大致意思是我们不关心可变状态,只要它不能被客户端代码发现。然而,人们仍然声称,即使可变状态影响局部变量(如我的第一个示例),代码也更具可读性或更容易推理。
就个人而言,我认为循环比递归更具可读性。
所以真正的问题是:为什么认为使用不可变变量的代码更易于阅读/推理?
【问题讨论】:
-
关于 1) 的重点是,如果您的数据结构首先是不可变的,则您不需要返回副本。
-
索引变量通常不会暴露,你是对的。只要我们谈论仅用于迭代的琐碎索引,我们就可以保存。这仍然不仅仅是一个最佳实践,因为这是您可以安全使用全局索引并且仍然可以保存线程的唯一方法。
-
回答您的最后一个问题:
def m() = { var x = 1; ... (20 lines of some code); x }。您需要扫描多少行才能知道返回的内容? (提示:20+)如果是val x = 1呢?
标签: scala functional-programming immutability