斯卡拉的元组解开细微差别

时间:2010-04-28 07:44:45

标签: scala design-patterns tuples

在尝试将元组解包为val时,我在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 个答案:

答案 0 :(得分:20)

是的,情况变得更糟:

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

以上将使用ClassCastException在运行时编译和失败。很容易忘记(i, j)声明是模式

编辑:对于 ziggystar ,Scala分配规则在声明中声明:

val p = expr //or var

p可以是标识符或模式(请参阅 Scala中编程部分15.7 ,pp284)。例如,以下内容有效:

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

将模式删除(即参数类型信息未被选中)这一事实意味着我的原始示例将被编译。

答案 1 :(得分:13)

[scala] Question about naming conventions您可以阅读

  

初始大写字母在模式匹配时具有优势。具有首字母大写字母的标识符被视为要匹配的值而不是要绑定的变量。

答案 2 :(得分:1)

如果您需要初始化大量常量并希望避免为每个常量编写val =或者您正在达到元组大小限制(22),则存在一种解决方法。

来自The Scala Language Specification的第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()