MatchError在匹配时收到IndexedSeq而不是LinearSeq

时间:2012-04-17 21:07:31

标签: scala match

match针对Seq编写的IndexedSeqLinearSeq类型上的工作方式是否与在import collection.immutable.LinearSeq object vectorMatch { def main(args: Array[String]) { doIt(Seq(1,2,3,4,7), Seq(1,4,6,9)) doIt(List(1,2,3,4,7), List(1,4,6,9)) doIt(LinearSeq(1,2,3,4,7), LinearSeq(1,4,6,9)) doIt(IndexedSeq(1,2,3,4,7), IndexedSeq(1,4,6,9)) doIt(Vector(1,2,3,4,7), Vector(1,4,6,9)) } def doIt(a: Seq[Long], b: Seq[Long]) { try { println("OK! " + m(a, b)) } catch { case ex: Exception => println("m(%s, %s) failed with %s".format(a, b, ex)) } } @annotation.tailrec def m(a: Seq[Long], b: Seq[Long]): Seq[Long] = { a match { case Nil => b case firstA :: moreA => b match { case Nil => a case firstB :: moreB if (firstB < firstA) => m(moreA, b) case firstB :: moreB if (firstB > firstA) => m(a, moreB) case firstB :: moreB if (firstB == firstA) => m(moreA, moreB) case _ => throw new Exception("Got here: a: " + a + " b: " + b) } } } } 类型上的方式不同?对我来说,无论输入类型如何,下面的代码似乎应该完全相同。当然它不会或我不会问。

OK! List(2, 3, 4, 7)
OK! List(2, 3, 4, 7)
OK! List(2, 3, 4, 7)
m(Vector(1, 2, 3, 4, 7), Vector(1, 4, 6, 9)) failed with scala.MatchError: Vector(1, 2, 3, 4, 7) (of class scala.collection.immutable.Vector)
m(Vector(1, 2, 3, 4, 7), Vector(1, 4, 6, 9)) failed with scala.MatchError: Vector(1, 2, 3, 4, 7) (of class scala.collection.immutable.Vector)

在2.9.1 final上运行它,我得到以下输出:

scalac -print

它适用于List-y的东西,但Vector-y的东西都失败了。我错过了什么吗?这是编译器错误吗?

m的{​​{1}}输出如下:

@scala.annotation.tailrec def m(a: Seq, b: Seq): Seq = {
  <synthetic> val _$this: object vectorMatch = vectorMatch.this;
  _m(_$this,a,b){
    <synthetic> val temp6: Seq = a;
    if (immutable.this.Nil.==(temp6))
      {
        b
      }
    else
      if (temp6.$isInstanceOf[scala.collection.immutable.::]())
        {
          <synthetic> val temp8: scala.collection.immutable.:: = temp6.$asInstanceOf[scala.collection.immutable.::]();
          <synthetic> val temp9: Long = scala.Long.unbox(temp8.hd$1());
          <synthetic> val temp10: List = temp8.tl$1();
          val firstA$1: Long = temp9;
          val moreA: List = temp10;
          {
            <synthetic> val temp1: Seq = b;
            if (immutable.this.Nil.==(temp1))
              {
                a
              }
            else
              if (temp1.$isInstanceOf[scala.collection.immutable.::]())
                {
                  <synthetic> val temp3: scala.collection.immutable.:: = temp1.$asInstanceOf[scala.collection.immutable.::]();
                  <synthetic> val temp4: Long = scala.Long.unbox(temp3.hd$1());
                  <synthetic> val temp5: List = temp3.tl$1();
                  val firstB: Long = temp4;
                  if (vectorMatch.this.gd1$1(firstB, firstA$1))
                    body%11(firstB){
                      _m(vectorMatch.this, moreA, b)
                    }
                  else
                    {
                      val firstB: Long = temp4;
                      val moreB: List = temp5;
                      if (vectorMatch.this.gd2$1(firstB, moreB, firstA$1))
                        body%21(firstB,moreB){
                          _m(vectorMatch.this, a, moreB)
                        }
                      else
                        {
                          val firstB: Long = temp4;
                          val moreB: List = temp5;
                          if (vectorMatch.this.gd3$1(firstB, moreB, firstA$1))
                            body%31(firstB,moreB){
                              _m(vectorMatch.this, moreA, moreB)
                            }
                          else
                            {
                              body%41(){
                                throw new java.lang.Exception("Got here: a: ".+(a).+("  b: ").+(b))
                              }
                            }
                        }
                    }
                }
              else
                {
                  body%41()
                }
          }

        }
      else
        throw new MatchError(temp6)
  }
};

3 个答案:

答案 0 :(得分:15)

::以外,您无法使用ListVector无法匹配,因为::是一个扩展List的案例类,因此其unapply方法不适用于Vector

val a :: b = List(1,2,3)    // fine
val a :: b = Vector(1,2,3)  // error

但您可以定义适用于所有序列的自己的提取器:

object +: {
  def unapply[T](s: Seq[T]) =
    s.headOption.map(head => (head, s.tail))
}

所以你可以这样做:

val a +: b = List(1,2,3)   // fine
val a +: b = Vector(1,2,3) // fine

答案 1 :(得分:0)

以下模式匹配适用于ListSeqLinearSeqIndexedSeqVector

  Vector(1,2) match {
  case a +: as => s"$a + $as"
  case _      => "empty"  
}

答案 2 :(得分:0)

在 Scala 2.10 中,object +: 是在 this commit 引入的。从那时起,对于每个 SeqLike,您可以:

@annotation.tailrec
def m(a: Seq[Long], b: Seq[Long]): Seq[Long] = {
  a match {
    case Nil => b
    case firstA +: moreA => b match {
      case Nil => a
      case firstB +: moreB if (firstB < firstA) => m(moreA, b)
      case firstB +: moreB if (firstB > firstA) => m(a, moreB)
      case firstB +: moreB if (firstB == firstA) => m(moreA, moreB)
      case _ => throw new Exception("Got here: a: " + a + "  b: " + b)
    }
  }
}

代码在 Scastie 运行。