在Scala中声明多个变量

Xav*_*avi 39 scala

我想使用val这样声明多个变量:

val a = 1, b = 2, c = 3
Run Code Online (Sandbox Code Playgroud)

但无论出于何种原因,这是一个语法错误,所以我最终使用了:

val a = 1
val b = 2
val c = 3
Run Code Online (Sandbox Code Playgroud)

要么

val a = 1; val b = 2; val c = 3;
Run Code Online (Sandbox Code Playgroud)

我个人觉得这两个选项都过于冗长而且有些丑陋.

有更好的选择吗?

另外,我知道Scala是一种经过深思熟虑的语言,为什么val a = 1, b = 2, c = 3语法不允许?

Dan*_*ral 69

琐碎的答案是将它们声明为元组:

val (a, b, c) = (1, 2, 3)
Run Code Online (Sandbox Code Playgroud)

这里可能有趣的是,这是基于模式匹配.实际发生的是你正在构建一个元组,然后通过模式匹配,将值赋值给a,bc.

让我们考虑一些其他模式匹配示例来进一步探索这个:

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"
Run Code Online (Sandbox Code Playgroud)

正如附注一样,rnd特别是该示例可以更简单地编写,而不用说明模式匹配,如下所示.

val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100)
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,您可以使用直观的"val x,y,z = 42"将多个val设置为相同的值. (17认同)
  • 值得注意的是,`val(a,b,c)=(1,2,3)`确实似乎是多次赋值的普遍接受的习语,比单独的赋值语句更可取.至少,这是我通过社区开发的代码阅读的印象. (2认同)
  • 还有`val seq @ Seq(a,b,c)= Seq(1,2,3)`它不仅定义了值'a`,`b`和`c`,还定义了seqeunce`seq` ! (2认同)

Dan*_*wak 24

丹尼尔的回答很好地总结了这样做的正确方法,以及它的工作原理.既然他已经涵盖了这个角度,我会尝试回答你更广泛的问题(关于语言设计)......

只要有可能,Scala就会努力避免添加语言功能,以支持通过现有机制处理事物.例如,Scala不包含break语句.但是,将您自己的一个作为库来滚动几乎是微不足道的:

case object BreakException extends RuntimeException

def break = throw BreakException

def breakable(body: =>Unit) = try {
  body
} catch {
  case BreakException => ()
}
Run Code Online (Sandbox Code Playgroud)

这可以通过以下方式使用:

breakable {
  while (true) {
    if (atTheEnd) {
      break
    }

    // do something normally
  }
}
Run Code Online (Sandbox Code Playgroud)

(注意:这包含在Scala 2.8的标准库中)

诸如Ruby(例如x = 1, y = 2, z = 3)之类的语言所允许的多种赋值语法属于"冗余语法"的类别.当Scala已经具有启用特定模式的功能时,它可以避免添加新功能以处理该模式的特殊情况.在这种情况下,Scala已经具有模式匹配(一般功能),可用于处理多个赋值(通过使用其他答案中概述的元组技巧).它没有必要以单独的方式处理特定的特殊情况.

稍微不同的是,值得注意的是C(以及Java的)多重赋值语法也是另一个更通用的特性的特例.考虑:

int x = y = z = 1;
Run Code Online (Sandbox Code Playgroud)

这利用了赋值返回C衍生语言中赋值的事实(以及赋值是右关联的事实).Scala不是这种情况.在Scala中,赋值返回Unit.虽然这确实有一些烦人的缺点,但它在理论上更有效,因为它直接强调了类型中赋值的副作用性质.


aka*_*ppi 16

我会在这里添加一个怪癖,因为它击中了自己,可能会帮助别人.

使用模式匹配时,sa在声明多个变量时,不要对变量使用Capital名称.它们在模式匹配中被视为类的名称,它也适用于此处.

  val (A,B)= (10,20)    // won't work
  println(A)
Run Code Online (Sandbox Code Playgroud)

错误消息并不能说明发生了什么:

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)
          ^
Run Code Online (Sandbox Code Playgroud)

我认为` - t会解决这个问题,但由于某些原因似乎没有(不确定,为什么不):

  val (`A`,`B`)= (10,20)
  println(A)
Run Code Online (Sandbox Code Playgroud)

即便如此,仍然存在相同的错误.

如果您知道如何使用带有大写变量名称的元组初始化模式,请发表评论.

  • 我厌恶Scala中标识符命名的"特征".如果你知道这件事就没问题了,但是它一直在绊倒人们(看到很多其他的SO问题)并且完全令人费解,直到你发生了什么事情...它有点像Fortan的"上帝是真实的 - 除非声明整数" (3认同)

Joe*_*Joe 7

如果你在一个元组中声明它们似乎有效

scala> val (y, z, e) = (1, 2, 45)
y: Int = 1
z: Int = 2
e: Int = 45
scala> e
res1: Int = 45
Run Code Online (Sandbox Code Playgroud)

虽然我可能会去个别陈述.对我来说这看起来更清楚:

val y = 1
val z = 2
val e = 45
Run Code Online (Sandbox Code Playgroud)

特别是如果变量有意义地命名.


sma*_*007 7

如果所有变量的类型相同并且采用相同的初始值,则可以执行此操作.

val a, b, c: Int = 0;
Run Code Online (Sandbox Code Playgroud)

  • 注意,"0"实际上是一个函数.用Math.random之类的东西替换它可以提供两个不同的值. (3认同)