2013-01-10 40 views
5

我只是学习在scala编程。 我在函数式编程方面有一些经验,就像我在面向对象编程中一样。 我的问题是一种简单,但棘手:斯卡拉不可变VS可变。应该怎么走?

Scala中应该使用哪些结构?我们是否应该坚持不变,例如。通过遍历它来修改列表并粘贴一个新的列表,或者进行mutables?你对此有什么看法,有什么表现方面,内存相关方面,...

我很可能在功能风格的程序,但它往往扩大到疯狂的努力量做的事情是很容易通过使用mutable来完成。这是情况依赖,使用什么?

+2

这个问题很一般。我强烈建议找出你认为需要“疯狂”努力来解决功能性问题,并提出有关问题的问题。您可能会学到新的功能性技巧,这些技巧会使努力看起来合理 - 甚至比使用可变数据更容易! –

+9

还有其他一些问题可以解决这个问题,这个问题太模糊或者太宽泛以至于不能接受一个好的答案,但是简而言之:做什么最好_overall_。作为一个经验法则,如果没有严重的缺点,请使用不可变的解决方案;在那之后,赞成一个可变状态,其中可变状态不会逃避本地环境(即,您正在使用的方法),然后是可变状态至少隐藏在类中的状态(因此不必担心它_使用多线程时不使用 - 并记录缺少线程安全性)。使用不变性,因为它可以帮助你,而不是当它伤害! –

+0

关于简单/疯狂的比例:在处理单个线程时,可变性通常更易于编程和调试,并且在使用多线程时变得非常难以编程和调试。 –

回答

3

(我想这一定是一个重复的,但不能很容易地找到更早的类似,所以我大胆地回答...)

没有一般的回答这个问题。斯卡拉创作者提出的经验法则是从不变的vals和结构开始,只要它有意义就坚持。您几乎总是可以通过这种方式为您的问题创建可行的解决方案。但是,如果没有,当然是务实的,并使用可变性。

一旦你有一个解决方案,你可以调整它,测试它,衡量它的表现等。如果你发现,例如,它太慢或太复杂,找出它的关键部分,了解是什么使它成为问题,并且 - 如果需要的话 - 使用可变变量重新实现它,理想的是保持它与程序的其余部分隔离。不过请注意,在许多情况下,更好的解决方案可以在不可变领域内找到,所以请先试着找那里。尤其对于像我这样的初学者来说,它仍然经常发生,我能想出的最佳解决方案看起来很扭曲和复杂,没有明显的方法来改进它 - 直到在几行代码中看到一个简单而优雅的解决方案,由经验丰富的Scala开发人员创建,该开发人员控制着语言及其库的更多功能。

+0

我也这么认为(必须有一个关于此的主题),并且四处看了看,但没有发现任何东西我想我会问这个问题。 Ty为你的答案,先生! – smoes

3

我通常遵循以下规则:

  • 切勿使用静态可变瓦尔

  • 保留所有用户定义的数据类型(通常情况下类)不可变的,除非它们是复制非常昂贵。这将简化很多应用程序逻辑。

  • 如果数据结构/集合本质上是可变的(即设计为随时间变化而变化),那么使用可变数据结构/集合可能是合适的。一个例子可能是当玩家移动时更新的大型游戏世界。请记住(几乎)永远不会在线程之间共享这些数据结构。

  • 它的优良的方法使用可变本地变量

  • 使用功能不变的结果集。这些可以严格或懒惰地评估,取决于在使用的环境中什么提供最佳性能。尽管如此,如果您使用依赖于可变集合的懒惰评估结果,请小心。

3

首选不可变为可变状态。只有在绝对必要时才使用可变状态。一些值得注意的原因包括:

  • 表现。标准库广泛使用变量和while循环,尽管这不是惯用的Scala。然而,这不应该被仿效,除非你有配置文件来确定修改代码更加必要会带来显着的性能增益。

  • I/O。 I/O或与外部世界的交互本质上是依赖于状态的,因此必须以可变的方式处理。

这与在所有主要语言中发现的建议编码风格没有什么不同,它们都是命令式的或功能性的。例如,在Java中,最好仅使用private final字段的数据对象。以不可变(和功能)方式编写的代码本质上更易于理解,因为当看到val时,他们知道它永远不会改变,从而减少任何特定对象或函数可能处于的状态数量。

在许多但它也允许自动并行执行,例如Scala中的集合类都具有par函数,该函数将返回一个并行集合,并行集合可以自动运行诸如mapreduce之类的函数。