在Odersky等人的Scala书中,他们说使用列表。我还没有阅读书籍封面,但所有的例子似乎都使用了val List。据我所知,人们也鼓励在vars上使用vals。但是在大多数应用程序中,使用var List或val MutableList之间没有权衡。显然我们可以使用val List。 但是使用大量var列表(或var Vectors等)是不错的做法?
我对来自C#的Scala很陌生。我有很多:
public List<T> myList {get; private set;}
如果C#内置不变性,很容易被声明为val的集合,因为集合本身在构造之后从未改变过,即使元素在其生命周期中被添加和减去。因此,声明var集合几乎感觉就像离不变性一样。
作为对答案和评论的回应,Scala的一个强大卖点是:它可以带来很多好处,而不必像Lisp或Haskell那样完全改变编写代码的方式。
答案 0 :(得分:15)
使用大量var列表(或var Vectors)是一种好习惯 等)?
我认为将var
与不可变集合一起使用比将val
与可变集合一起使用更好。在我的头顶,因为
您对行为有更多保证:如果您的对象有可变列表,您永远不知道是否有其他外部对象要更新它
你限制了可变性的程度;返回集合的方法将产生一个不可变的方法,因此您只能在一个对象中具有可变性
通过简单地将var赋值给val来使var变得容易,而要使可变集合成为不可变的,你必须使用不同的集合类型并重建它
在某些情况下,例如具有大量I / O的时间相关应用程序,最简单的解决方案是使用可变状态。在some情况下,可变解决方案更优雅。但是在大多数代码中,您根本不需要可变性。关键是使用具有更高阶函数的集合而不是循环,或者如果不存在合适的函数则使用递归。这比听起来简单。您只需要花一些时间来了解List(以及其他大多数相同的集合)上的方法。最重要的是:
map
:将您提供的函数应用于集合中的每个元素 - 使用而不是循环和更新数组中的值
foldLeft
:从集合中返回单个结果 - 使用而不是循环和更新累加器变量
for-yield
表达式:简化映射和过滤,尤其是嵌套循环类型问题
最终,大部分功能编程都是不变性的结果,你不可能没有另一个;但是,本地变量主要是一个实现细节:只要它不能从本地范围中逃脱,就有一点可变性没有错。因此,使用具有不可变集合的变量,因为本地变量不是将要导出的变量。
答案 1 :(得分:8)
您假设List
必须是可变的,或者指向它的任何内容都必须是可变的。换句话说,您需要选择以下两个选项之一:
val list: collection.mutable.LinkedList[T]
var list: List[T]
这是一种错误的二分法。你可以同时拥有:
val list: List[T]
所以,您应该问的问题是我该怎么做?,但我们只能在您尝试并面对特定问题时回答这个问题。没有通用的答案可以解决你所有的问题(好吧,有 - monad和递归 - 但是太通用)。
所以......试一试。您可能有兴趣查看Code Review,其中大多数Scala问题都与如何使某些代码更具功能性有关。但是,最终,我认为最好的方法是尝试,并在你无法弄清楚某些特定问题时诉诸Stack Overflow。
答案 2 :(得分:1)
以下是我在函数式编程中看到这个可变性问题的方法。
最佳解决方案:值是最好的,因此函数式编程使用中最好的是值和递归函数:
val myList = func(4);
def func(n) = if (n>0) n::func(n) else Nil
需要多变的东西:有时需要可变的东西或者让一切变得更容易。当我们面对这种情况时,我的印象是使用mutables结构,所以使用val list: collection.mutable.LinkedList[T]
代替var list: List[T]
,这不是因为对性能的真正改进,而是因为已经定义的可变函数可变的集合。
这个建议是个人的,当你想要表现时可能不推荐,但它是我在scala中用于日常编程的指南。
答案 3 :(得分:1)
我相信您不能将可变val
/不可变var
的问题与特定用例区分开来。让我加深一点:你想问自己有两个问题:
var
。原因是使用可变val
这样做的唯一方法是通过防御性副本。val
,并通过一个不可修改的包装器返回它(很像Collections.unmodifiableList()
在Java中所做的那样,here是一个问题所在的问题。 s询问如何在Scala中这样做)。我认为没有办法用一个不变的var实现这个,所以我相信你的选择是强制性的。var
,您可以直接返回内部表示,因此可能会稍微更清楚。var
成为更好的选择:您可以将输入中的内容分配给当前状态,并且您已经很好了。使用不可变val
,您需要首先清除您的集合,然后复制新内容。绝对更糟。trait
只是暴露方法,用于逐步操纵其状态。在这种情况下,可变性val
通常可能在性能方面更好,但如果这是一个问题,我建议您查看Scala's collections performance。答案 4 :(得分:0)
如果有必要使用var列表,为什么不呢?为避免出现问题,您可以限制变量的范围。不久之前有一个类似的问题,答案非常好:scala's mutable and immutable set when to use val and var。