Scala's tuple unwrapping nuance

雨燕双飞 提交于 2019-12-03 08:10:55

问题


I've noticed the following behavior in scala when trying to unwrap tuples into vals:

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

Is that because scala's pattern matching mechanism automatically presumes that all identifiers starting with capitals within patterns are constants, or is that due to some other reason?

Thanks!


回答1:


Yes, and it gets worse:

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

The above will compile and fail at runtime with a ClassCastException. It is easy to forget that the (i, j) declaration is a pattern.

EDIT: for ziggystar, the Scala assignment rules state that in the statement:

val p = expr //or var

p can be either an identifier or a pattern (see section 15.7 of Programming in Scala, pp284). So for example, the following is valid:

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

Taking this together with the fact that patterns are erased (i.e. parametric type information is unchecked) means that my original example will compile.




回答2:


From [scala] Question about naming conventions you can read

The initial capital letter has an advantage when pattern matching. Identifiers with an initial capital letter are considered to be values to match against instead of a variable to be bound.




回答3:


A workaround exists if you need to initialize a large number of constants and want to avoid writing val = for each or you are hitting the tuple size limit (22).

From section 4.1 of The Scala Language Specification:

A value definition val x: T = e defines x as a name of the value that results from the evaluation of e. A value definition val p1, ..., pn = e is a shorthand for the sequence of value definitions val p1 = e; ...; val pn = e.

Per the specification, one can initialize a sequence of values all with names starting with capital letters by specifying an expression on the right-hand which returns each value in order.

val iter = Iterator(1, 2, 3)
val A, B, C = iter.next()

Another example:

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

In these trivial cases above this approach is not very useful. Below is a more useful example that initializes a constant for each of the 64 squares of the chessboard (see Square.scala#L31 for source):

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()


来源:https://stackoverflow.com/questions/2727612/scalas-tuple-unwrapping-nuance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!