对于大多数语言我都不会问"为什么他们这样做X?"因为它通常基于意见。
对于像C ++这样的语言,通常的答案是引用一些规范,并且所有人都可以说,在做出特定选择之前,有人可能认为很长很难(但可能做出了不同的选择)。
Scala是不同的 - 通常答案是指出你可以用一些更简单的结构Y和Z来思考X,因此在这种情况下看X的表达是有意义的。
因此,我会问为什么Scala允许引入多个名称的定义并为每个名称计算一次给定表达式?
如果你让Java程序员猜测这里会发生什么,他们可能会猜错:
var x, y, z = 3
即。他们只猜测z
被分配了一个值。
如果您解释val
然后告诉他们以下内容是合法的:
val x, y, z = 3
然后他们可能会猜到正在进行更多操作,因为x
和y
必须在此行之后有值,因为以后无法为它们分配不同的值。
他们可能会认为x
和y
为其类型采用了默认值,例如0表示整数,但由于此处没有明确的类型,这是一个跳跃。
他们可能会认为它被处理为:
val z = 3
val x = z
val y = z
=
左边的表达式产生原始值或不可变对象时,这并不重要。但以下可能让他们有理由怀疑:
val x, y, z = new StringBuilder
为什么有人想为同一个StringBuilder
实例引入三个名称?
如果你向他们展示了以下内容,他们可能会从构造中猜出,甚至在运行代码之前出现了一些奇怪的事情:
var i = 0
def f: Int = {
i += 1
println(i)
i
}
val x, y, z = f
有人最终意识到,似乎只与z
相关联的表达式对每个名称实际评估一次,即上述内容相当于:
val x = f
val y = f
val z = f
那么谈论习惯于的其他语言的程序员可能会思考一下,这甚至是有趣的吗?
大多数人从其他地方来到像Scala这样的语言,所以除非有充分的理由,否则应避免使用可能令人困惑的程度结构。
乍一看这个功能似乎并没有多大提供,它避免了你不得不重复自己,但是为了这么小的收益而添加这段相当混乱的语法糖似乎很奇怪。
那么在某种情况下会带来真正的好处吗?或者这里没有真正的收益,例如我们与其他地方建立的更广泛的模式保持某种逻辑一致性?
答案 0 :(得分:5)
有一种情况是使用这个令人惊讶的功能:定义scala.Enumeration
:
object Weekday extends scala.Enumeration {
val Monday, Tuesday, Wednesday, Thursday, Friday = Value
}
调用Value
(从def
继承的Enumeration
)5次,对于每个枚举字段调用一次。实际上,这为每个字段分配了一个Enumeration#Value
的新实例,这显然是枚举有用的必要条件。
如果没有这种多重赋值功能,您必须写:
object Weekday extends scala.Enumeration {
val Monday = Value
val Tuesday = Value
val Wednesday = Value
val Thursday = Value
val Friday = Value
}
我从未见过在Enumeration
声明中使用的其他任何地方使用多重赋值功能。
在语言设计方面这是否是个好主意是一个主观问题,而且SO不适合讨论它。
答案 1 :(得分:2)
你已基本回答了自己的问题。选择在val x, y, z = someComplexExpression
含义
val z = someComplexExpression
val y = z
val x = z
或
val x = someComplexExpression
val y = someComplexExpression
val z = someComplexExpression
或根本不被允许。第一个是糟糕的选择有两个原因:
您提到第一个:您通常不需要为同一个实例提供多个名称。
如果您选择第一个,则每次需要第二个时都必须复制someComplexExpression
,或者将其提取到方法中。如果你选择第二个,在你需要的时候写第一个(尽管第1点)是微不足道的:
val z = someComplexExpression
val x, y = z
不允许这样做。在看到你的评论之前,我认为我从未真正看过它。但是一旦被允许就删除它是一个坏主意。
显然var x, y, z = ...
需要与此保持一致。