Scala - 使用Either的递归模式匹配

时间:2014-10-24 16:25:04

标签: scala matching either

我目前看起来像这样:

data foreach {
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(a))))))))))))))))))) => /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(a)))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Left(Right(a))))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Left(Right(a)))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Left(Right(a))))))) =>  /* Do something */
          case Left(Left(Left(Left(Left(Right(a)))))) =>  /* Do something */
          case Left(Left(Left(Left(Right(a))))) =>  /* Do something */
          case Left(Left(Left(Right(a)))) =>  /* Do something */
          case Left(Left(Right(a))) =>  /* Do something */
          case Left(Right(a)) =>  /* Do something */
          case Right(a) =>  /* Do something */
        }

我想知道是否有任何方法可以实现某种递归功能,使我的模式匹配更清晰。看起来更像是这样的东西:

data foreach {
          case Foo(a, 3) =>  /* Do something */
          case Foo(a, 2) =>  /* Do something */
          case Foo(a, 1) =>  /* Do something */
          case Foo(a, 0) =>  /* Do something */
        }

1 个答案:

答案 0 :(得分:1)

我就是这样做的。

object Test extends App {
  object Foo {
    def unapply[T: Manifest](e: Either[_, T]): Option[(T, Int)] = e match {
      case Right(rVal: T) => Some(Tuple2(rVal, 0))
      case Left(left: Either[_, T]) => left match {
        case Foo(rVal: T, d) => Some(Tuple2(rVal, d + 1))
        case _ => None
      }
      case _ => None
    }

    def apply[T, E <: Either[E, T]](t: T, d: Int): Either[E, T] = {
      Either.cond[E, T](d == 0, t, apply(t, d - 1).asInstanceOf[E])
    }
  }

  val data = List(
    Foo("a", 0),
    Foo("b", 2),
    Foo("c", 3),
    Foo("d", 10),
    Left(10)
  )

  data foreach println
  println()

  data collect {
    case Foo(a, 0) => println(s"$a at 0")
    case Foo(a, d) => println(s"Generic: $a at $d")
  }
}

此测试应用有此输出:

// Right(a)
// Left(Left(Right(b)))
// Left(Left(Left(Right(c))))
// Left(Left(Left(Left(Left(Left(Left(Left(Left(Left(Right(d)))))))))))
// Left(10)
//
// a at 0
// Generic: b at 2
// Generic: c at 3
// Generic: d at 10