对Scala 2.8收集行为感到非常沮丧。这是问题:我正在创建一个数独板。我将单元格从A1标记为I9(字母为行,数字为列)。我想得到一个单元列表,即9行,夜间列和夜间象限。
这是我的scala类:
class Square(val row:Char, val column:Int) extends Pair[Char, Int](row, column) {
override def toString() = "" + row + column
}
object Board {
private val rows = "ABCDEFGHI"
private val cols = 1 to 9
private lazy val units = unitList(rows, cols)
private def cross(rows:Iterable[Char], columns:Iterable[Int]):Iterable[Square] = {
for (row <- rows; col <- columns)
yield new Square(row, col)
}
private def unitList(rows:Iterable[Char], cols:Iterable[Int]) = {
val u1 = (for (col <- cols) yield cross(rows, List(col)))
val u2 = (for (row <- rows) yield cross(List(row), cols))
val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows))
u1 :+ u2 :+ u3 // won't compile, reason: :+ is not a member of Iterable[Iterable[sudoku.Square]]
}
def run() {
val u1 = (for (col <- cols) yield cross(rows, List(col)))
val u2 = (for (row <- rows) yield cross(List(row), cols))
val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows))
println(u1)
println(u2)
println(u3)
val u4 = u1 :+ u2 :+ u3 // compiles
println(u1 :+ u2 :+ u3) // compiles and output correctly
}
}
请参阅代码中的注释。具体来说,为什么相同的代码不能在unitList中编译,但在run()中编译并运行良好?
另外,当我观察run方法的输出时,yield关键字返回的集合似乎是在Vector和List之间随机切换:
Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9))
Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9))
List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9))
Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9), Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9)), List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9)))
我完全迷失在这里。
答案 0 :(得分:8)
for comprehension中的yield的结果来自第一个生成器的类型,在你的方法中,你约束参数的类型到目前为止你丢失了:+方法。
//The type of 1 to 9 is show below
scala> 1 to 9
res0: scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
//If you cast it to Iterable[Int] it doens't have the :+ method
scala> (res0:Iterable[Int]) :+ 1
<console>:7: error: value :+ is not a member of Iterable[Int]
(res0:Iterable[Int]) :+ 1
^
//But if you don't, you have it
scala> res0 :+ 1
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 1)
//And to prove that for comprehensions yield derives the type of the first generator:
scala> for(a <- res0) yield a
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> for(a <- (res0:Iterable[Int])) yield a
res8: Iterable[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9)
答案 1 :(得分:3)
尽管存在非常奇怪的行为,但:+
不可能成为您想要的运营商。由于您没有注释unitList
的返回类型,我不知道您的期望。我假设您想要返回Iterable[Square]
或Iterable[Iterable[Square]]
。因此,让我们看看如何获取它们,以及为什么:+
不正确。
首先,u1
,u2
和u3
都是Iterable[Iterable[Square]]
,但确切的子类型会有所不同。这应该很容易理解:cross
会返回Iterable[Square]
,因此在for-comprehension中产生cross
会产生Iterable[Iterable[Square]]
。
接下来,让我们考虑:+
。此方法会向集合添加元素,因此,如果u1
为Iterable(a, b, c)
,其中a,b和c为Iterable[Square]
,则u1 :+ u2
为Iterable(a, b, c, u2)
,其类型变为Iterable[X]
,其中X
是Iterable[Square]
(a,b和c的类型)和Iterable[Iterable[Square]]
(u2
的类型的统一)。最终结果是Iterable[Iterable[AnyRef]]
。
由于u1
,u2
和u3
的类型基本相同,所以可能的正确操作是:
u1 ++ u2 ++ u3
将返回Iterable[Iterable[Square]]
。现在,如果要删除嵌套并返回Iterable[Square]
,可以将其展平:
(u1 ++ u2 ++ u3).flatten
这两件事中的一件可能是你想要的。
现在,对于“随机”切换,它没有任何随机性。在每种情况下,都有两个for-comprehension,结果集合的实际实现取决于原始集合的实现。所以,让我们考虑一下:
Range
,内部类型来自String
(第一个要交叉的参数)String
,内部类型来自List
(第一个要交叉的参数)List
,内部类型派生自String
(第一个要交叉的参数)因此可以很容易地推断出,对String
(WrappedString
,实际上)和Range
的理解导致Vector
,而对{{1}的理解导致List
。
答案 2 :(得分:2)
发生编译错误是因为:+
是IndexedSeq
(因此List
)的成员,而不是Iterable
的成员。如果您从
unitList
的返回值
u1 :+ u2 :+ u3
到
List(u1) :+ u2 :+ u3
它编译得很好。