Spray中的FormFieldMagnet如何工作?

时间:2013-10-14 09:20:52

标签: scala implicit-conversion spray

我清楚地知道Spray中的磁铁是如何容易的,但是FieldDefMagnet中的所有转换和隐含只是让我的脑筋流露。以下是sources

中的部分
def formField(fdm: FieldDefMagnet): fdm.Out = fdm()

trait FieldDefMagnet {
  type Out
  def apply(): Out
}
object FieldDefMagnet {
  implicit def apply[T](value: T)(implicit fdm2: FieldDefMagnet2[T]) = new FieldDefMagnet {
    type Out = fdm2.Out
    def apply() = fdm2(value)
  }
}
trait FieldDefMagnet2[T] {
  type Out
  def apply(value: T): Out
}
object FieldDefMagnet2 {
  implicit def apply[A, B](implicit fdma: FieldDefMagnetAux[A, B]) = new FieldDefMagnet2[A] {
    type Out = B
    def apply(value: A) = fdma(value)
  }
}

trait FieldDefMagnetAux[A, B] extends (A ⇒ B)

因此,当我打电话时,formField("name") scalac在"name"中包裹了FieldDefMagnet.apply("name"),但是如何选择和应用其他含义?

1 个答案:

答案 0 :(得分:1)

是的,它就像你对FieldDefMagnet.apply所说的那样开始,然后继续查找apply方法的含义,以此类推,看看完整的隐含链。

粗略地说,FieldDefMagnet是1)用2)隐式功能注释的值和3)来自功能的返回类型。

FieldDefMagnet2只是具有返回类型的类型成员的隐式功能。

FieldDefMagnetAux只为Out类型成员提供了更简单的语法。它也可以写成(也许我们应该这样做)

type FieldDefMagnetAux[A, B] = FieldDefMagnet2[A] { type Out = B }

这种结构基本上需要以一种使scala编译器推断出大多数类型参数的方式来引导类型推断。

所有“有趣”的东西都发生在FieldDefMagnetAux中,对于不同类型的输入类型,可以找到相应的功能。

编辑:要查看它的实际效果,请考虑formField("name")扩展为

的扩展
formField(
    FieldDefMagnet.apply[String]("name")(
      FieldDefMagnet2.apply[String, Directive1[String]](
        FieldDefMagnetAux.forString(
          Deserializer.fromRequestUnmarshaller[spray.http.HttpForm](
            Deserializer.fromMessageUnmarshaller[spray.http.HttpForm](
              Deserializer.formUnmarshaller(
                Deserializer.UrlEncodedFormDataUnmarshaller, Deserializer.MultipartFormDataUnmarshaller))), 
          FormFieldConverter.dualModeFormFieldConverter[String](
            Deserializer.liftToSourceOption[String, String](
              Deserializer.fromFunction2Converter[String, String](Predef.conforms[String])), 
            Deserializer.liftFromEntityOptionUnmarshaller[String](
              Deserializer.liftToSourceOption[spray.http.HttpEntity, String](
                Deserializer.StringUnmarshaller)))))))