0

我从楼梯书上了解了提取器:

    object Twice {
      def apply(x: Int) = x * 2
      def unapply(x: Int) = if(x % 2 == 0) Some(x / 2) else None
    }
    // outside pattern mathcing, Twice.apply(21) is called
    val x = Twice(21)
    x match {
        // inside pattern matching, Twice.unapply(x) is called,
        // the result Some(21) is matched against y,
        // y gets the value 21
      case Twice(y) => println(x + " is twice " + y)
      case _ => println(x + " is odd.")
    }

这很简单。但是今天我从一些关于 Play 框架的书中读到了这段代码:

trait RequestExtractors extends AcceptExtractors {

  //Convenient extractor allowing to apply two extractors. 
  object & { 
    def unapply(request: RequestHeader): Option[(RequestHeader, RequestHeader)] = Some((request, request)) 
  } 

}

//Define a set of extractors allowing to pattern match on the Accept HTTP header of a request 
trait AcceptExtractors {

  //Common extractors to check if a request accepts JSON, Html, etc. 
  object Accepts { 
    import play.api.http.MimeTypes 
    val Json = Accepting(MimeTypes.JSON) 
    val Html = Accepting(MimeTypes.HTML) 
    val Xml = Accepting(MimeTypes.XML) 
    val JavaScript = Accepting(MimeTypes.JAVASCRIPT) 
  } 

}

//Convenient class to generate extractors checking if a given mime type matches the Accept header of a request. 
case class Accepting(val mimeType: String) {
  def unapply(request: RequestHeader): Boolean = request.accepts(mimeType) 
  def unapply(mediaRange: play.api.http.MediaRange): Boolean = mediaRange.accepts(mimeType) 
}


def fooBar = Action { 
    implicit request => 
      val xmlResponse: Node = <metadata> 
        <company>TinySensors</company> 
        <batch>md2907</batch> 
      </metadata> 

      val jsonResponse = Json.obj("metadata" -> Json.arr( 
        Json.obj("company" -> "TinySensors"), 
        Json.obj("batch" -> "md2907")) 
      ) 

      render { 
        case Accepts.Xml() => Ok(xmlResponse) 
        case Accepts.Json() & Accepts.JavaScript() => Ok(jsonResponse) 
      }
  }

unapply函数返回 Boolean 而不是 Option 时,提取器如何工作?在这里工作怎么&Accepts.Xml

4

2 回答 2

1

好的,我找到了一种通过做一个最小的例子来解决这个问题的方法:

object Unapply {

  case class DividedBy(val number: Int) {
    def unapply(divider: Int): Boolean = number % divider == 0
    def unapply(divider: Double): Boolean = number % divider.toInt == 0
  }

  val x = DividedBy(15)
  // y should be true
  val y = 5 match {
  //    case DividedBy(15)() => true
    case x() => true
    case _ => false
  }
}

奇怪的是,当您使用DividedBy(15)()(上面注释掉)时,代码将无法编译。


更新:

object Unapply {
  case class Division(val number: Int) {
//    def unapply(divider: Int): Boolean = number % divider == 0
    def unapply(divider: Int): Option[(Int, Int)] = if (number % divider == 0) Some(number/divider, 0) else None
    def unapply(divider: Double): Boolean = number % divider.toInt == 0
  }

  object Division {
    def apply(number: Int) = new Division(number)
  }

  val divisionOf15 = Division(15)
  // y should be true
  val y = 5 match {
  //    case DividedBy(15)() => true
    case divisionOf15(z, w) => s"$z, $w"
    case _ => s"Not divisible"
  }

  val z = 5.0 match {
    case divisionOf15() => "Divisible"
    case _ => "Not divisible"
  }
}

在阅读了一些关于楼梯书的旧笔记之后,我对这一点有了更清晰的理解。案例类是一个提取器工厂。

于 2016-01-10T21:15:34.967 回答
1

我真的可以告诉你有关播放框架的信息,但如果用于模式匹配,则返回布尔值的提取器表示模式是否匹配。因此,如果提取器返回 true,则意味着模式与值匹配。这是关于提取器的一个很好的链接,也涵盖了这种情况: http ://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html

通常,您将提取器用于两个用例:

1) 破坏一个对象,这意味着返回一个或多个表示给定对象状态的值

2)您还可以在模式匹配期间使用提取器将对象转换为另一种对象。我为这个案例做了一个小例子:

class Division(val number: Int) {
}

object Division {
    def unapply(divider: Division): Boolean = divider.number != 0

    def unapply(divider: Int): Option[Division] = if (divider != 0) Some(new Division(divider)) else None
}

val divident = 15
val divider = 5
val y = divider match {
    case Division(notZero) => divident / notZero.number //notZero is of type Division
    case _ => throw new IllegalArgumentException()
}
于 2016-01-10T21:19:46.113 回答