使用未应用功能丰富 PartialFunction

enrich PartialFunction with unapply functionality

PartialFunction 是一个天然的提取器,它的 lift 方法提供了精确的提取器功能。所以使用部分函数作为提取器会非常方便。这将允许以比可用于 PartialFunction

的普通 orElse 更复杂的方式组合模式匹配表达式

所以我尝试使用 pimp 我的库方法但失败了


更新:如@Archeg 所示,还有另一种有效的转换方法。所以我将它包含在提供的代码中。

我也尝试了一些更复杂的解决方案,但都失败了


object Test {
  class UnapplyPartial[-R, +T](val fun : PartialFunction[R,T]) {
    def unapply(source : R) : Option[T] = fun.lift(source)
  }
  implicit def toUnapply[R,T](fun : PartialFunction[R,T]) : UnapplyPartial[R,T] = new UnapplyPartial(fun)

  class PartialFunOps[-R, +T](val fun : PartialFunction[R,T]) {
    def u : UnapplyPartial[R, T] = new UnapplyPartial(fun)
  }
  implicit def toPartFunOps[R,T](fun : PartialFunction[R,T]) : PartialFunOps[R,T] = new PartialFunOps(fun)


  val f : PartialFunction[String, Int] = {
    case "bingo" => 0
  }
  val u = toUnapply(f)

  def g(compare : String) : PartialFunction[String, Int] = {
    case `compare` => 0
  }

   // error while trying to use implicit conversion
  def testF(x : String) : Unit = x match {
    case f(i) => println(i)
    case _ => println("nothing")
  }

  // external explicit conversion is Ok
  def testU(x : String) : Unit = x match {
    case u(i) => println(i)
    case _ => println("nothing")
  }

 // embedded explicit conversion fails
  def testA(x : String) : Unit = x match {
    case toUnapply(f)(i) => println(i)
    case _ => println("nothing")
  }

  // implicit explicit conversion is Ok
  def testI(x : String) : Unit = x match {
    case f.u(i) => println(i)
    case _ => println("nothing")
  }

  // nested case sentences fails
  def testInplace(x : String) : Unit = x match {
    case { case "bingo" => 0 }.u(i) => println(i)
    case _ => println("nothing")
  }

  // build on the fly fails
  def testGen(x : String) : Unit = x match {
    case g("bingo").u(i) => println(i)
    case _ => println("nothing")
  }

  // implicit conversion without case is also Ok
  def testFA(x : String) : Option[Int] =
    f.unapply(x)
}

我收到以下错误消息:

UnapplyImplicitly.scala:16: error: value f is not a case class, nor does it have an unapply/unapplySeq member case f(i) => println(i)

UnapplyImplicitly.scala:28: error: '=>' expected but '(' found. case toUnapply(f)(i) => println(i)

使用 TestI 所示的假设形式可以避免此错误。但我很好奇是否可以避免 testInplace 错误:

UnapplyImplicitly.scala:46: error: illegal start of simple pattern case { case "bingo" => 0 }.u(i) => println(i) ^

UnapplyImplicitly.scala:47: error: '=>' expected but ';' found. case _ => println("nothing")

UnapplyImplicitly.scala:56: error: '=>' expected but '.' found. case g("bingo").u(i) => println(i) ^

我不确定你最终想要达到什么目的,但据我所知,提取器应该始终是对象,你无法通过 class 获得它。它实际上在文档中被称为 Extractor Object 。考虑一下:

class Wrapper[R, T](fun: PartialFunction[R, T]) {
  object PartialExtractor {
    def unapply(p: R): Option[T] = fun.lift(p)
  }
}

implicit def toWrapper[R,T](fun : PartialFunction[R,T]) : Wrapper[R, T] = new Wrapper(fun)


val f : PartialFunction[String, Int] = {
  case "bingo" => 0
}

def testFF(x : String) : Unit = x match {
  case f.PartialExtractor(i) => println(i)
  case _ => println("nothing")
}

更新

我能想到的最好的:

def testInplace(x : String) : Unit ={
  val ff = { case "bingo" => 0 } : PartialFunction[String, Int]
  x match {
   case ff.PartialExtractor(Test(i)) => println(i)
   case "sd" => println("nothing") }
}