【发布时间】:2019-04-17 07:26:56
【问题描述】:
我想了解下面这行背后的机制:
val List(x) = Seq(1 to 10)
这种机制的名称是什么?这与类型转换相同,还是发生了其他事情? (在 Scala 2.11.12 中测试。)
【问题讨论】:
我想了解下面这行背后的机制:
val List(x) = Seq(1 to 10)
这种机制的名称是什么?这与类型转换相同,还是发生了其他事情? (在 Scala 2.11.12 中测试。)
【问题讨论】:
该机制称为模式匹配。
这里是官方文档:https://docs.scala-lang.org/tour/pattern-matching.html
这也适用于推导式:
for{
People(name, firstName) <- peoples
} yield s"$firstName $name"
以你为例:
val List(x) = Seq(1 to 10)
x 是该列表的内容 - 在您的情况下为 Range 1 to 10(您有一个包含一个元素的列表)。
如果您确实有一个包含多个元素的列表,则会引发异常
val List(x) = (1 to 10).toList // -> ERROR: undefined
所以正确的模式匹配应该是:
val x::xs = (1 to 10).toList
现在x 是第一个元素(头部),xs 是其余元素(尾部)。
【讨论】:
scala.collection.immutable.Range.Inclusive,而不是List[scala.collection.immutable.Range.Inclusive]。
我怀疑你的问题实际上是表达式
Seq(1 to 10)
这不会创建一个包含 10 个元素的序列,而是创建一个包含单个 Range 对象的序列。所以当你这样做时
val List(x) = Seq(1 to 10)
x 已分配给该 Range 对象。
如果您想要List 的数字,请执行以下操作:
(1 to 10).toList
模式 List(x) 仅在右侧的表达式是包含单个元素的 List 的实例时才会匹配。它不会匹配空的List 或具有多个元素的List。
在这种情况下它恰好可以工作,因为Seq 的构造函数实际上返回了List 的一个实例。
【讨论】:
val List(x) = Seq(1 to 10) 运行但val List(x) = Seq(1, 2) 抛出MatchError?
List(x) 是匹配List 的构造函数模式,它保留一个与x 匹配的元素。 Seq(1, 2) 是一个Seq,它包含两个元素,因此无法与上述模式成功匹配。
val List(x, y) = Seq(1, 2) 和val List(x) = Seq(1),它会起作用,因为您拥有正确数量的元素。
这种技术称为对象解构。 Haskell 提供了类似的功能。 Scala 使用模式匹配来实现这一点。
本例中使用的方法是 Seq#unapplySeq: https://www.scala-lang.org/api/current/scala/collection/Seq.html
【讨论】:
你可以想到
val <pattern> = <value>
<next lines>
作为
<value> match {
case <pattern> =>
<next lines>
}
仅当<pattern> 只是一个变量或具有类型的变量时才会发生这种情况。
【讨论】: