簡體   English   中英

如何在 Scala 中找到隱式的來源?

[英]How can I locate where an implicit comes from in Scala?

簡短的問題:

有沒有辦法讓 Scala 編譯器告訴我在程序中給定點使用的某個隱式在哪里聲明?

如果沒有,是否有我可以手動遵循的算法來找出隱式聲明的位置?

長問題:

我正在遵循簡單的噴霧 crud 教程

在下面的代碼片段中( 教程的這個repo):

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

as需要一個FromRequestUnmarshaller[T]類型的隱式(完整源代碼在這里):

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

當我問 IntelliJ 這個隱式來自哪里(使用 CMD+SHIFT+P)時,我得到:

在此處輸入圖片說明 當我遵循第一個提示時,我得到了這個:

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

在此處輸入圖片說明

我檢查了看起來可能包含這種隱含的特征,例如這個特征,但它不包含隱含的:

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編譯器告訴我哪里有一定隱含的(在這個例子中FromRequestUnmarshaller[T]在程序中給定的點使用(在本例這里)被宣布?

如果沒有,是否有我可以手動遵循的算法來找出隱式聲明的位置?

我在 Google/SOF 上尋找這個問題,但我發現的提示沒有幫助。 我也經歷過這個,但我仍然不知道FromRequestUnmarshaller[T]來自哪里。

通常我在編譯器中啟用-Xlog-implicits以查看-Xlog-implicits發生了什么。

此外,spray 已被棄用,取而代之的是 akka-http。 我建議切換。

我這樣做了(正如邁克爾的評論中所建議的那樣):

    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 的搜索使用功能:

在此處輸入圖片說明

Odersky 從他的書中推薦的調試隱式的方法是使用-Xprint:typer運行scalac ,您可以在此處查看詳細信息

復制在這里:

    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)
    }
  }

再次歸功於奧德斯基: https ://www.artima.com/pins1ed/implicit-conversions-and-parameters.html#21.7

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM