Scala元组的解包细微差别

16
我注意到在尝试将元组解包为常量时,在Scala中会出现以下行为:

我注意到在Scala中尝试将元组解包为常量时会出现以下行为:

scala> val (A, B, C) = (1, 2, 3)
<console>:5: error: not found: value A
       val (A, B, C) = (1, 2, 3)
            ^
<console>:5: error: not found: value B
       val (A, B, C) = (1, 2, 3)
               ^
<console>:5: error: not found: value C
       val (A, B, C) = (1, 2, 3)
                  ^

scala> val (u, v, w) = (1, 2, 3)
u: Int = 1
v: Int = 2
w: Int = 3

这是因为Scala的模式匹配机制会自动假设模式中以大写字母开头的所有标识符都是常量,还是由于其他原因呢?

谢谢!

3个回答

21

没错,而且情况还会变得更糟糕:

val (i, j) : (Int, Int) = "Hello" -> "World"

以上代码能够编译通过,但在运行时会抛出ClassCastException异常。很容易忘记(i,j)声明是一个模式

编辑:对于ziggystar,Scala赋值规则表明,在语句中:

val p = expr //or var

p 可以是一个标识符或模式(请参见《Scala编程》第15.7节,第284页)。例如,以下代码是有效的:

val x :: y :: z :: rest = List(1, 2, 3, 4)

结合模式被擦除的事实(即参数化类型信息未经检查),这意味着我的原始示例将编译。


这很有趣。但是我不明白你在这里所说的模式是什么意思。你能否再解释一下? - ziggystar
5
有趣的错误...也许你应该指出它失败的原因是因为它等同于Tuple2[Int, Int],而它被类型擦除为Tuple2[Any, Any] - Daniel C. Sobral

13

[scala] Question about naming conventions中,您可以阅读到:

当进行模式匹配时,首字母大写有一个优势。以首字母大写开头的标识符被视为要匹配的值,而不是要绑定的变量。


1
如果您需要初始化大量常量并且想要避免为每个常量编写val =或者您达到了元组大小限制(22),则存在一种解决方法。
来自Scala语言规范第4.1节:

值定义val x:T = e将x定义为从e的评估结果中获得的值的名称。 值定义val p1,...,pn = e是值定义val p1 = e; ...; val pn = e的简写。

根据规范,可以通过在右侧指定一个按顺序返回每个值的表达式来初始化以大写字母开头的一系列值的名称。
val iter = Iterator(1, 2, 3)
val A, B, C = iter.next()

另一个例子:

val next = { var n = 0; () => { n = n + 1; n } }
val A, B, C, D, E, F, G, H = next()

在这些琐碎的情况下,这种方法并不是很有用。下面是一个更有用的例子,它为棋盘上的64个方格中的每一个初始化了一个常量(请参见Square.scala#L31的源代码):
val squareIter = squares.iterator
val A1, A2, A3, A4, A5, A6, A7, A8,
  B1, B2, B3, B4, B5, B6, B7, B8,
  C1, C2, C3, C4, C5, C6, C7, C8,
  D1, D2, D3, D4, D5, D6, D7, D8,
  E1, E2, E3, E4, E5, E6, E7, E8,
  F1, F2, F3, F4, F5, F6, F7, F8,
  G1, G2, G3, G4, G5, G6, G7, G8,
  H1, H2, H3, H4, H5, H6, H7, H8 = squareIter.next()

谢谢。好主意。第一个例子甚至可以更短:val A、B、C = (Iterator(1, 2, 3).next _)() - far.be
1
谢谢,但是缩写版本与第一个示例不等价。表达式(Iterator(1, 2, 3).next _)()计算为1,然后将ABC设置为1 - Dave Swartz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接