【问题标题】:How can I locate where an implicit comes from in Scala?如何在 Scala 中找到隐式的来源?
【发布时间】:2017-05-13 22:31:29
【问题描述】:

小问题:

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

如果没有,是否有一种算法可以让我手动查找隐式声明的位置?

长问题:

我正在关注简单的喷雾剂tutorial

在下面的代码 sn-p 中(来自教程的this repo):

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)时,我得到:

当我关注第一个 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 中的:

我检查了看起来可能包含此隐含的特征,例如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]来自哪里。

【问题讨论】:

标签: scala intellij-idea implicit spray


【解决方案1】:

通常我在编译器中启用-Xlog-implicits 以查看隐式发生了什么。

spray 也不赞成使用 akka-http。我建议切换。

【讨论】:

  • 我试过了,它没有告诉我隐式来自哪里,它只抱怨尝试过但没有工作的隐式:(
【解决方案2】:

我这样做了(正如迈克尔评论中所建议的那样):

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

【讨论】:

    【解决方案3】:

    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

    【讨论】:

      猜你喜欢
      • 2018-09-12
      • 2017-04-04
      • 2019-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多