scala - Akka-Http DSL 发生了什么?

标签 scala dsl implicit-conversion akka-http

最近刚接触akka,在学习akka-http的时候,被Rest API DSL吸引,这里有一段代码:

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
import scala.io.StdIn

object WebServer {
   def main(args: Array[String]) {
      implicit val system = ActorSystem("my-system")
      implicit val materializer = ActorMaterializer()
      // needed for the future flatMap/onComplete in the end
      implicit val executionContext = system.dispatcher
      val route =
         path("hello") {
            get {
               complete("Say hello to akka-http")
            }
         }
      val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
      println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
      StdIn.readLine() // let it run until user presses return
      bindingFuture
         .flatMap(_.unbind()) // trigger unbinding from the port
         .onComplete(_ => system.terminate()) // and shutdown when done
   }
}

我无法理解的是 val route = path("hello") {....}。我知道“path”方法会返回一个指令,“get”方法也是一个指令,但我不明白一个指令如何通过大括号“{}”“嵌入”到另一个指令中。

我知道,一定有一些隐式转换,通过调试,我看到,应用了以下隐式转换:akka.http.scaladsl.server.Directive#addByNameNullaryApply

implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route =
  r ⇒ directive.tapply(_ ⇒ r)

谁能给我解释一下:这种隐式转换是如何被选择和发生的? apply 和 tapply 尝试做什么?非常感谢!

最佳答案

首先:

val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)

等于:

val bindingFuture = Http().bindAndHandle(Route.handlerFlow(route), "localhost", 8080)

Route.handlerFlow 方法用于将Route 转换为Flow[HttpRequest, HttpResponse, NotUsed],正如我们看到的bindAndHandle 接受 handler 类型是:Flow[HttpRequest, HttpResponse, Any]

隐式转换routeFlow[HttpRequest, HttpResponse, NotUsed]是由RouteResult.route2HandlerFlow实现的>。这由 Directives 扩展并与 import akka.http.scaladsl.server.Directives._ 一起使用。

因此当您导入指令时,您导入了这个隐式转换。

对于addByNameNullaryApply,我们可以重写如下代码:

...
val path1: Directive0 = path("hello")
val contextToEventualResult: Route = get(complete("Say hello to akka-http"))
val route: Route = path1.apply(contextToEventualResult)
...

正如我们所见,对于 path1.apply(contextToEventualResult),它调用了一个高阶函数,并应用了 contextToEventualResult 参数。但是 path1 的类型是 Directive0,所以:

implicit def addByNameNullaryApply(directive: Directive0): (⇒ Route) ⇒ Route 用于将 Directive0 类型转换为高阶函数 类型:(⇒ Route) ⇒ Route

关于scala - Akka-Http DSL 发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40252952/

相关文章:

c - 为什么C比较3等于3.0?

list - 如何找到具有最小值的元素的索引?

scala - 在 Scala 中重写,按数组类型区分的重载 Java 方法

java - 内联领域特定语言以生成 Java 代码

python - 嵌入式用户定义表达式的安全实现策略

image-processing - 用于 Clojure 图像合成的 DSL

scala - 从 Spark 数据框中选择几列,并以列列表作为开始

scala - 如何使用Scala解压缩简明的(hadoop文件格式)文件

scala - 在参数化类中混合通用特征而不重复类型参数

短裤上的 C# 按位运算 - 为什么要转换为 int?