我只是在学习用scala编程。我在函数式编程方面有一些经验,就像我在面向对象编程方面一样。我的问题很简单,但很棘手:
Scala 中应该使用哪些结构?我们应该只坚持不可变,例如。通过遍历列表来修改列表并将新列表粘在一起,还是选择可变列表?您对此有何看法,性能方面,内存相关方面是什么,...
我可能会以函数式编程,但它通常会扩展为疯狂的工作量来完成使用可变变量很容易完成的事情。它取决于情况,使用什么?
我只是在学习用scala编程。我在函数式编程方面有一些经验,就像我在面向对象编程方面一样。我的问题很简单,但很棘手:
Scala 中应该使用哪些结构?我们应该只坚持不可变,例如。通过遍历列表来修改列表并将新列表粘在一起,还是选择可变列表?您对此有何看法,性能方面,内存相关方面是什么,...
我可能会以函数式编程,但它通常会扩展为疯狂的工作量来完成使用可变变量很容易完成的事情。它取决于情况,使用什么?
更喜欢不可变状态而不是可变状态。仅在绝对必要时使用可变状态。一些值得注意的原因包括:
表现。标准库广泛使用 var 和 while 循环,即使这不是 Scala 惯用的。但是,这不应该被模仿,除非您已经分析确定将代码修改为更具命令性将带来显着的性能提升的情况。
输入/输出。I/O 或与外部世界的交互本质上是依赖于状态的,因此必须以可变的方式处理。
这与所有主要语言(命令式或函数式)中推荐的编码风格没有什么不同。例如,在 Java 中,最好使用只有private final
字段的数据对象。以不可变(和函数式)方式编写的代码本质上更容易理解,因为当人们看到 a 时val
,他们知道它永远不会改变,从而减少了任何特定对象或函数可能处于的状态数量。
在许多情况下,它还允许自动并行执行,例如,Scala 中的集合类都有一个par
函数,该函数将返回一个并行集合,该集合会自动运行对类似map
或reduce
并行函数的调用。
(我认为这一定是重复的,但无法轻易找到较早的类似的,所以我冒昧地回答......)
这个问题没有一般的答案。Scala 的创建者建议的经验法则是从不可变的 val 和结构开始,只要有意义就坚持下去。您几乎总是可以通过这种方式为您的问题创建一个可行的解决方案。但如果不是,当然要务实并使用可变性。
一旦有了解决方案,您就可以对其进行调整、测试、测量其性能等。如果您发现例如它太慢或过于复杂,确定它的关键部分,了解它的问题所在,并且 - 如果需要 - 使用可变变量重新实现它,理想情况下使其与程序的其余部分隔离。请注意,在许多情况下,也可以从不可变领域中找到更好的解决方案,因此请先尝试查看那里。特别是对于像我这样的初学者来说,我能想出的最佳解决方案仍然经常发生,看起来扭曲而复杂,没有明显的改进方法——直到在几行代码中看到一个简单而优雅的解决同一问题的解决方案,由经验丰富的 Scala 开发人员创建,他控制了该语言及其库的更多功能。
我通常遵守以下规则:
永远不要使用静态可变变量
保持所有用户定义的数据类型(通常是案例类)不可变,除非它们的复制成本非常高。这将简化很多应用程序逻辑。
如果数据结构/集合本质上是可变的(即它被设计为随时间变化),则使用可变数据结构/集合可能是合适的。一个例子可能是一个随着玩家移动而更新的大型游戏世界。请记住(几乎)永远不要在线程之间共享这些数据结构。
在方法中使用可变局部变量很好
对函数结果使用不可变集合。这些可以根据在使用的上下文中提供最佳性能的内容进行严格或惰性评估。如果您使用依赖于可变集合的延迟评估结果,请小心。