我想使用val
来声明多个变量:
val a = 1, b = 2, c = 3
但无论出于何种原因,这是一个语法错误,所以我最终使用了:
val a = 1
val b = 2
val c = 3
或
val a = 1; val b = 2; val c = 3;
我个人认为这两种选择都过于冗长而且有点难看。
有更好的选择吗?
另外,我知道Scala是一种经过深思熟虑的语言,为什么不允许使用val a = 1, b = 2, c = 3
语法?
答案 0 :(得分:69)
简单的回答是将它们声明为元组:
val (a, b, c) = (1, 2, 3)
这里可能有趣的是,这是基于模式匹配。实际发生的是你正在构建一个元组,然后通过模式匹配将值分配给a
,b
和c
。
让我们考虑一些其他模式匹配示例来进一步探讨这一点:
val DatePattern = """(\d{4})-(\d\d)-(\d\d)""".r
val DatePattern(year, month, day) = "2009-12-30"
val List(rnd1, rnd2, rnd3) = List.fill(3)(scala.util.Random.nextInt(100))
val head :: tail = List.range(1, 10)
object ToInt {
def unapply(s: String) = try {
Some(s.toInt)
} catch {
case _ => None
}
}
val DatePattern(ToInt(year), ToInt(month), ToInt(day)) = "2010-01-01"
正如旁注,特别是rnd
示例可以更简单地编写,而不会说明模式匹配,如下所示。
val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100)
答案 1 :(得分:24)
Daniel的回答很好地总结了这样做的正确方法,以及它的工作原理。由于他已经涵盖了这个角度,我将尝试回答你更广泛的问题(关于语言设计)......
尽可能地,Scala努力避免添加语言功能,以支持通过现有机制处理事物。例如,Scala不包含break
语句。然而,将你自己的一个作为一个库推出几乎是微不足道的:
case object BreakException extends RuntimeException
def break = throw BreakException
def breakable(body: =>Unit) = try {
body
} catch {
case BreakException => ()
}
可以通过以下方式使用:
breakable {
while (true) {
if (atTheEnd) {
break
}
// do something normally
}
}
(注意:这包含在Scala 2.8的标准库中)
像Ruby这样的语言(例如x = 1, y = 2, z = 3
)允许的多种赋值语法属于“冗余语法”类别。当Scala已经具有启用特定模式的功能时,它可以避免添加新功能以处理该模式的特殊情况。在这种情况下,Scala已经具有模式匹配(一般功能),可用于处理多个赋值(通过使用其他答案中概述的元组技巧)。它没有必要以单独的方式处理特定的特殊情况。
稍微不同的是,值得注意的是C(以及Java的)多重赋值语法也是另一个更通用的特性的特例。考虑:
int x = y = z = 1;
这利用了赋值返回C衍生语言中赋值的事实(以及赋值是右关联的事实)。 Scala不是这种情况。在Scala中,赋值返回Unit
。虽然这确实有一些恼人的缺点,但它在理论上更有效,因为它直接在其类型中强调了赋值的副作用。
答案 2 :(得分:16)
我会在这里添加一个怪癖,因为它击中了自己并可能帮助其他人。
使用模式匹配时,s.a。在声明多个变量时,不要对变量使用Capital名称。它们在模式匹配中被视为类的名称,它也适用于此。
val (A,B)= (10,20) // won't work
println(A)
错误消息并不能说明发生了什么:
src/xxx.scala:6: error: not found: value A val (A,B)= (10,20) ^ src/xxx.scala:6: error: not found: value B val (A,B)= (10,20) ^ src/xxx.scala:7: error: not found: value A println(A) ^
我认为` - t会解决这个问题,但由于某些原因似乎并不(不确定,为什么不):
val (`A`,`B`)= (10,20)
println(A)
即使是那样的错误也是如此。
如果您知道如何使用带有大写变量名称的元组初始化模式,请发表评论。
答案 3 :(得分:7)
如果你在元组中声明它们似乎有用
scala> val (y, z, e) = (1, 2, 45)
y: Int = 1
z: Int = 2
e: Int = 45
scala> e
res1: Int = 45
虽然我可能会去个别陈述。对我来说这看起来更清楚:
val y = 1
val z = 2
val e = 45
特别是如果变量有意义地命名。
答案 4 :(得分:7)
如果所有变量属于同一类型且采用相同的初始值,则可以执行此操作。
val a, b, c: Int = 0;