如何找到Scala中隐含的来源?

时间:2016-12-29 15:14:10

标签: scala intellij-idea implicit spray

简短问题:

有没有办法让scala编译器告诉我某个程序中给定点的隐式使用声明在哪里?

如果没有,是否有一个我可以手动跟踪的算法来找出自己声明隐式的位置?

长问题:

我正在关注简单的喷雾tutorial

在下面的代码段中(来自教程的this个回购站):

pathEnd {
  post {
    entity(as[Question]) { question =>
      completeWithLocationHeader(
        resourceId = questionService.createQuestion(question),
        ifDefinedStatus = 201, ifEmptyStatus = 409)
      }
    }
} ~

as隐含FromRequestUnmarshaller[T]类型(完整来源here):

  def as[T](implicit um: FromRequestUnmarshaller[T]) = um

当我问IntelliJ这个隐含来自哪里时(使用CMD + SHIFT + P),我得到:

enter image description here 当我按照第一个hint时,我得到了这个:

trait UnmarshallerLifting {

  implicit def fromRequestUnmarshaller[T](implicit um: FromMessageUnmarshaller[T]): FromRequestUnmarshaller[T] =
    new FromRequestUnmarshaller[T] {
      def apply(request: HttpRequest): Deserialized[T] = um(request)
    }
...

这无助于我找出隐式FromRequestUnmarshaller[T]的来源,因为如果我检查类层次结构,我无法弄清楚特征UnmarshallerLifting如何混合到QuestionResource中: / p>

enter image description here

我检查看起来可能包含此隐含的特征,例如this特征,但它不包含隐含的字符:

trait MarshallingDirectives {
  import BasicDirectives._
  import MiscDirectives._
  import RouteDirectives._

  /**
   * Unmarshalls the requests entity to the given type passes it to its inner Route.
   * If there is a problem with unmarshalling the request is rejected with the [[spray.routing.Rejection]]
   * produced by the unmarshaller.
   */
  def entity[T](um: FromRequestUnmarshaller[T]): Directive1[T] =
    extract(_.request.as(um)).flatMap[T :: HNil] {
      case Right(value)                            ⇒ provide(value)
      case Left(ContentExpected)                   ⇒ reject(RequestEntityExpectedRejection)
      case Left(UnsupportedContentType(supported)) ⇒ reject(UnsupportedRequestContentTypeRejection(supported))
      case Left(MalformedContent(errorMsg, cause)) ⇒ reject(MalformedRequestContentRejection(errorMsg, cause))
    } & cancelAllRejections(ofTypes(RequestEntityExpectedRejection.getClass, classOf[UnsupportedRequestContentTypeRejection]))

  /**
   * Returns the in-scope FromRequestUnmarshaller for the given type.
   */
  def as[T](implicit um: FromRequestUnmarshaller[T]) = um

  /**
   * Uses the marshaller for the given type to produce a completion function that is passed to its inner route.
   * You can use it do decouple marshaller resolution from request completion.
   */
  def produce[T](marshaller: ToResponseMarshaller[T]): Directive[(T ⇒ Unit) :: HNil] =
    extract { ctx ⇒ (value: T) ⇒ ctx.complete(value)(marshaller) } & cancelAllRejections(ofType[UnacceptedResponseContentTypeRejection])

  /**
   * Returns the in-scope Marshaller for the given type.
   */
  def instanceOf[T](implicit m: ToResponseMarshaller[T]) = m

  /**
   * Completes the request using the given function. The input to the function is produced with the in-scope
   * entity unmarshaller and the result value of the function is marshalled with the in-scope marshaller.
   */
  def handleWith[A, B](f: A ⇒ B)(implicit um: FromRequestUnmarshaller[A], m: ToResponseMarshaller[B]): Route =
    entity(um) { a ⇒ RouteDirectives.complete(f(a)) }
}

object MarshallingDirectives extends MarshallingDirectives
在看了20个不同的地方后,我感到很沮丧。

有没有办法让scala编译器告诉我在程序的给定点(在本例中为here)中使用了某个隐式(在本例中为FromRequestUnmarshaller[T])的位置?

如果没有,是否有一个我可以手动跟踪的算法来找出自己声明隐式的位置?

我在Google / SOF上查找了这个问题,但我发现的提示并没有帮助。我也经历了this,我仍然不知道FromRequestUnmarshaller[T]来自哪里。

3 个答案:

答案 0 :(得分:4)

通常我会在编译器中启用-Xlog-implicits来查看带有隐含的内容。

此外,不推荐使用spray来支持akka-http。我建议切换。

答案 1 :(得分:4)

我这样做了(正如Michael的评论所示):

    import scala.reflect.runtime.universe.reify
    println(reify(entity(as[Question])))

打印出来:

Expr[spray.routing.Directive1[spray_examples.plain_rest.danielasfregola.quiz.management.entities.Question]](QuestionResource.entity(QuestionResource.as[Question](Deserializer.fromRequestUnmarshaller(Deserializer.fromMessageUnmarshaller(QuestionResource.json4sUnmarshaller(ManifestFactory.classType(classOf[spray_examples.plain_rest.danielasfregola.quiz.management.entities.Question])))))))

这直接告诉隐含来自哪里:Deserializer.fromRequestUnmarshaller

此外,通过使用InteliJ的搜索使用功能,这是另一种方式:

enter image description here

答案 2 :(得分:0)

Odersky建议的从his book隐式调试的方法是与scalac一起运行-Xprint:typer,您可以在here中详细了解。

此处复制:

    object Mocha extends Application {
  
      class PreferredDrink(val preference: String)
  
      implicit val pref = new PreferredDrink("mocha")
  
      def enjoy(name: String)(implicit drink: PreferredDrink) {
        print("Welcome, "+ name)
        print(". Enjoy a ")
        print(drink.preference)
        println("!")
      }
  
      enjoy("reader")
    }
  $ scalac -Xprint:typer mocha.scala
  [[syntax trees at end of typer]]
// Scala source: mocha.scala
  package <empty> {
    final object Mocha extends java.lang.Object with Application
        with ScalaObject {
  
      
// ...
  
      private[this] val pref: Mocha.PreferredDrink =
        new Mocha.this.PreferredDrink("mocha");
      implicit <stable> <accessor>
        def pref: Mocha.PreferredDrink = Mocha.this.pref;
      def enjoy(name: String)
          (implicit drink: Mocha.PreferredDrink): Unit = {
        scala.this.Predef.print("Welcome, ".+(name));
        scala.this.Predef.print(". Enjoy a ");
        scala.this.Predef.print(drink.preference);
        scala.this.Predef.println("!")
      };
      Mocha.this.enjoy("reader")(Mocha.this.pref)
    }
  }

再次归功于Odersky:https://www.artima.com/pins1ed/implicit-conversions-and-parameters.html#21.7