【问题标题】:Pattern Matching Assignment in ScalaScala 中的模式匹配分配
【发布时间】:2016-03-29 08:49:54
【问题描述】:

我有一个关于通过 scala 中的模式匹配进行分配的问题。假设我有以下内容:

a. Seq.unapplySeq(List(1))

b. val Seq(z) = List(1)

c. val c = List(1) match {
  case Seq(e) => e
}

d. List.unapplySeq(Seq(1))

e. val List(a) = Seq(1)

f. val b = Seq(1) match {
  case List(e) => e
}

只有 (d) 不编译,其他编译运行正常。

我知道 List 的 unapplySeq 在 SeqFactory 中定义为:

abstract class SeqFactory[CC[X] <: Seq[X] with GenericTraversableTemplate[X, CC]] extends GenSeqFactory[CC] with TraversableFactory[CC] {
    applySeq[A](x: CC[A]): Some[CC[A]] = Some(x)
}

因为 CC 是 List,所以 (d) 中的 Seq 不会进行类型检查。

似乎 (a)、(b) 和 (c) 在一组中,而 (d)、(e) 和 (f) 在另一组中。

在我的理解中,(f) 的破坏实际上会调用 (d),因为 (f) 中的模式匹配所做的是使用 List 来破坏 Seq(1)。

我的问题是为什么 (e) 和 (f) 在 (d) 无法编译的情况下仍然正确。

【问题讨论】:

    标签: scala pattern-matching


    【解决方案1】:

    我可能有一个不谈论SeqFactory的答案给你:

    1. (e) 编译并运行,因为Seq(1)Seq.apply(2) 的快捷方式,它总是方便地给出List 实例,即。这里List(2)*。因此它可以与 (b) 情况同化。
    2. (f) 出于相同的上述原因编译和运行(Seq(1) 给出与case List(e) 匹配的List(1)
    3. (d) 无法编译,因为我在第一点中所说的 (e) 案例是关于 instance 而不是 type,即。 Seq(1)List 的实例,但类型为 Seq。这是一个演示:

      List.unapplySeq(Seq(1))
      

      等价于

      List.unapplySeq(List(1).asInstanceOf[Seq[Int]])
      

      并给予:

      *error: type mismatch;*
      

      而:

      List.unapplySeq(List(1))
      

      相当于:

      List.unapplySeq(Seq(1).asInstanceOf[List[Int]])
      

      两者都给出:

      Some(List(1))
      

    但是,困难在于,你有一点关于 (f) 模式匹配的好奇心:它的行为就像 scala 在内部将其键入为 List 而不是 Seq

    这是我的解释模式匹配不关心输入的类型。就这么简单(例如,参见https://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#variable-patterns)。这是一个演示:

        var foo: Seq[Int] = List(1)
        foo match { case _: List[Int] => true } // gives true
        foo = 1 to 3
        foo match { case _: List[Int] => true } // throws scala.MatchError
    

    希望对你有帮助。

    *为了更清楚一点,如果在另一个 scala 实现中,Vector(2) 将由这个应用代替,错误将不是在编译期间而是在运行时弹出(Alexey Romanov 对此提出了很好的观点)。

    【讨论】:

    • 问题是为什么 (e) 和 (f) compile,编译器不知道“Seq.apply(2) 总是方便地给出一个 List 实例” .
    • 确实,我使用“工作”一词,这对于“编译和运行”来说可能是不明确的。我会马上修改,谢谢。
    • 要表明 Seq(1) 返回 List 实例对编译没有影响:尝试 (Vector(1): Seq[Int]) match { case List(e) =&gt; e }。它编译(并且在运行时不匹配,正如预期的那样)。
    • 我同意你的观点,并希望它对你有所帮助,因为问题是关于编译等等。
    • 我假设您可能会建议我的回答需要澄清。另外,我冒昧地添加了一个脚注并在其中提及您。希望我是明智的,否则,请不要犹豫。
    【解决方案2】:

    (e) 被翻译成 (f),正确。但是如果您查看https://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#pattern-sequencesunapplySeq 的唯一要求是结果类型,而不是参数类型。所以我的猜测(规范实际上并没有具体说明这一点,我目前无法检查)是(f)在调用unapplySeq之前测试它的参数是List,即它在内部类似于

    Seq(1) match {
        case canUnapplySeq: List[Int] => 
            ... List.unapplySeq(canUnapplySeq) // (d) only invoked here
    }
    

    请注意,该参数也适用于 unapply

    【讨论】:

      猜你喜欢
      • 2012-10-31
      • 2016-05-17
      • 2021-12-17
      • 2019-05-26
      • 1970-01-01
      • 1970-01-01
      • 2014-09-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多