Lau*_*eng 2 dsl scala 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
}
}
Run Code Online (Sandbox Code Playgroud)
我无法理解的是val route = path("hello") {....}.我知道"path"方法将返回一个指令,而"get"方法也是一个指令,但我无法理解指令如何通过大括号"{}""嵌入"另一个指令.
我知道,必须有一些隐式转换,通过调试,我看到,应用了以下隐式转换: akka.http.scaladsl.server.Directive#addByNameNullaryApply
implicit def addByNameNullaryApply(directive: Directive0): (? Route) ? Route =
r ? directive.tapply(_ ? r)
Run Code Online (Sandbox Code Playgroud)
任何人都可以向我解释一下:如何选择并发生这种隐式转换?什么剂量的适用和tapply尝试做?非常感谢!
第一:
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
Run Code Online (Sandbox Code Playgroud)
等于:
val bindingFuture = Http().bindAndHandle(Route.handlerFlow(route), "localhost", 8080)
Run Code Online (Sandbox Code Playgroud)
该Route.handlerFlow方法用于转换Route为Flow[HttpRequest, HttpResponse, NotUsed],因为我们看到bindAndHandleaccept handler类型是:Flow[HttpRequest, HttpResponse, Any]
的隐式转换 route到Flow[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)
...
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的,因为path1.apply(contextToEventualResult)它通过应用参数调用高阶函数contextToEventualResult.但对于path1's类型是Directive0,所以:
implicit def addByNameNullaryApply(directive: Directive0): (? Route) ? Route用于将Directive0类型转换为高阶函数,类型为:(? Route) ? Route.