我是新来斯卡拉,有一个很难理解声明和使用功能的所有方式。有人可以解释,一步一步来,这到底是怎么回事呢?
我下面,介绍阿卡HTTP的课程。代码工作,但我不明白的路线方法:
import akka.http.scaladsl.server.Directives._
def route = path("hello") {
get {
complete("Hello, World!")
}
}
我们正在定义一个被定义route
的值(从上面的线进口)的方法path
,但随后的path
函数里面我们有一些所谓get
,我不明白。
而当我声明path
作为一种方法,我会重写它,或者这是怎么回事?
我希望如果有人能解释什么是行,行去。并且不介意它是阿卡参与。我想了解一下Scala的语法。
=================================================================
感谢所有伟大的答案。我想我明白了!
所以,总结一下我的版本的它。
path()
是想要一个字符串的函数。它返回想要一个Directive
其他功能。而在斯卡拉的行话,我们可以做一些哗众取宠直接发送一个指令返回的功能。
因此,在该块一切{}被发送到path()
回报功能。而且,由于在斯卡拉块总是返回的最后一行,我们正在返回其用同样的原则,我们与get
致电complete
。
get
也是一个功能,即采用一个参数,并且可被写为一个块。这相当于只是写get(complete("Hello, world"))
。
再次感谢!
你不一定需要了解的一切在这个答案阿卡HTTP的有效使用,但我保证你会有时间,可能宜早不宜迟,你将与编译器以及战斗将只是希望所有花哨的语法糖走开,好消息是,有一些工具来实现这个功能(坏消息是,一旦你摆脱花哨的语法的现实可能是一个可怕的混乱)。
要注意的第一件事是,虽然大括号这里可能看起来很像来自Java或其他语言的范围或定义分隔符,他们真的只是应用方法的参数。你可以用括号同样的事情:
scala> import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Directives._
scala> val route = path("hello")(get(complete("Hello, World!")))
route: akka.http.scaladsl.server.Route = ...
虽然这些get
和complete
东西可能看起来像关键字或什么的,他们是在Directives
真的只是静态方法(约阅读完整故事这件事),所以下面也相当于:
scala> import akka.http.scaladsl.server.Directives
import akka.http.scaladsl.server.Directives
scala> val route = Directives.path("hello")(
| Directives.get(Directives.complete("Hello, World!"))
| )
route: akka.http.scaladsl.server.Route = ...
这有望解释了一些语法,但仍然有很多无形的东西会在这里。如果你在一个REPL的时候,你可以使用Scala的,反映的reify
作为一个非常有用的工具,以帮助使这个东西可见。
要开始使用一个简单的(无关)例如,您可能当你看到Scala代码像"a" * 3
,特别是如果你知道Java字符串不具有*
运营商,所以你打开一个REPL不知道发生了什么:
scala> import scala.reflect.runtime.universe.reify
import scala.reflect.runtime.universe.reify
scala> reify("a" * 3).tree
res6: reflect.runtime.universe.Tree = Predef.augmentString("a").$times(3)
还有的脱糖版本,显示出真实被应用到字符串给它*
操作的隐式方法。
你的情况,你可以写这样的事情:
scala> import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Directives._
scala> import scala.reflect.runtime.universe.reify
import scala.reflect.runtime.universe.reify
scala> reify(path("hello")(get(complete("Hello, World!")))).tree
res0: reflect.runtime.universe.Tree = Directive.addByNameNullaryApply(Directives.path(Directives._segmentStringToPathMatcher("hello"))).apply(Directive.addByNameNullaryApply(Directives.get).apply(Directives.complete(ToResponseMarshallable.apply("Hello, World!")(Marshaller.liftMarshaller(Marshaller.StringMarshaller)))))
我们可以重新格式化为可读性物化表达:
Directive.addByNameNullaryApply(
Directives.path(
Directives._segmentStringToPathMatcher("hello")
)
).apply(
Directive.addByNameNullaryApply(Directives.get).apply(
Directives.complete(
ToResponseMarshallable.apply("Hello, World!")(
Marshaller.liftMarshaller(Marshaller.StringMarshaller)
)
)
)
)
如果添加了几个进口,这也是完全合法的Scala代码:
scala> import akka.http.scaladsl.server.{ Directive, Directives }
import akka.http.scaladsl.server.{Directive, Directives}
scala> import akka.http.scaladsl.marshalling.{ Marshaller, ToResponseMarshaller }
import akka.http.scaladsl.marshalling.{Marshaller, ToResponseMarshaller}
scala> val route = Directive.addByNameNullaryApply(
| Directives.path(
| Directives._segmentStringToPathMatcher("hello")
| )
| ).apply(
| Directive.addByNameNullaryApply(Directives.get).apply(
| Directives.complete(
| ToResponseMarshallable.apply("Hello, World!")(
| Marshaller.liftMarshaller(Marshaller.StringMarshaller)
| )
| )
| )
| )
route: akka.http.scaladsl.server.Route = ...
为了解释这个一步一步,我们可以path("hello")
开始。我们可以从the API docs看到Directives.path
并不需要一个字符串,而是一个PathMatcher
,所以我们知道,从String
的隐式转换到PathMatcher
被踢了,在我们完全脱糖的版本,我们可以看到,在这里:
Directives.path(
Directives._segmentStringToPathMatcher("hello")
)
果然,如果我们检查的文档,_segmentStringToPathMatcher
是合适类型的隐式转换。
类似的事情也发生在complete("Hello, World!")
。 Directives.complete
需要ToMarshallableResponse
,不是String
,所以必须有一个隐式转换在踢。在这种情况下,它ToResponseMarshallable.apply
,这也需要一个隐含的Marshaller
情况下,在这种情况下,它通过隐式转换都会从ToEntityMarshaller
到ToResponseMarshallable
,其中ToEntityMarshaller
实例Marshaller.StringMarshaller
,和转换器是Marshaller.liftMarshaller
部分:
Directives.complete(
ToResponseMarshallable.apply("Hello, World!")(
Marshaller.liftMarshaller(Marshaller.StringMarshaller)
)
)
还记得我上面说的get
是在Directives
只是一个静态方法?这是一种骗人的,在这个意义上,虽然它是Directives
一个静态方法,我们不叫它当我们写get(...)
。相反,这get
居然是返回Directive0
一个无参数的方法。 Directive0
为Directive[Unit]
一个类型别名,虽然Directive[Unit]
不具有apply
方法,它可以被隐式转换成做的事情,经由上addByNameNullaryApply
的Directive
方法。所以,当你写get(...)
,斯卡拉desugars,要get.apply(...)
然后get
值转换为Route => Route
功能,它有一个适当的apply
方法。而同样的事情与path("hello")(...)
部分发生。
这种事情可能看起来像一场噩梦,作为一个长期的Scala用户,我可以告诉你,这绝对往往是。像reify
和API文档的工具可以让它少一点可怕,虽然。
在您的片断有Scala语言和编译器的几个特点,我们来分析一下我知道的那些:
def route = ...
定义不带参数,并用其通过身体的返回值确定的结果类型的功能。
path("hello") {
...
}
我不熟悉的path
功能本身,但它好像有三样东西在片段事情:
我不想花时间来描述它们作为互联网是充满了极大地解释它们的资源。但我想至少this great introductory article,帮助了我很多在我的早年链接。
链接的文章显示您如何使用所有三个特性来构建自己的控制结构,就像你正在使用的代码的一个完整的例子。
移动的,位
get {
...
}
再次是以上几点的应用程序,但这次有没有哗众取宠所以花括号给函数的唯一参数。
complete("Hello, World!")
只是一个普通的老函数调用。
总之该代码使用转换函数调用到sometehing类似于一种特殊的语言结构,这可以为初学者打造的混乱一些“招数”。
这种技术经常用于在Scala中写领域特定语言(DSL)。
但是也有一些这里发生了很多事情,这是一个相当复杂的例子来理解阶。但我会尽力。
该route
的类型是Route
,其被定义为type Route = RequestContext ⇒ Future[RouteResult]
一个类型别名其中RequestContext ⇒ Future[RouteResult]
是消耗RequestContext
并产生Future[RouteResult]
的功能。
path
是创建Directive[Unit]
的方法。存在这样转换Directive[Unit]
成一个函数Route => Route
(简化的)的隐式转换。函数可以通过方法apply
或编译器糖作为(???)
或{???}
被调用。
get
是创建Directive[Unit]
过的方法和类似的方法适用于它。
complete
是延伸StandardRoute
类型Route
的。
知道了这些,我们可以丑化你的榜样将被写成
path("hello").apply { ctx =>
val inner: Route = { ctx =>
ctx.complete("done")
}
get.apply(inner).apply(ctx)
}
它可能会帮助,如果你看到的代码片段是这样的:
量akka.http.scaladsl.server.Directives._
def route: Route = path("hello") {
get {
complete("Hello, World!")
}
}
我添加Route
类型,以显示你,你是简单地构建使用由阿卡HTTP提供了一种语法,允许你在更高层次定义公共匹配的标准巢该部分内的特定条件的路由,和。在这里,您使用的是在阿卡HTTP路由DSL功能。路由DSL带来了一些implicits到范围。使用路径方法可确保您能够处理进入主机的路径host/hello
,这意味着你的主机现在可以处理获取其路径/hello
请求的请求。路径指令中的代码体代表其他匹配标准来检查的时候,我们有一个正确的路径匹配。完整的方法,知道如何转换为HttpResponse
。在这里,您可以通过“世界你好”,一个纯文本完成。
你可能有额外的HTTP方法标准的要求,是POST,PUT,删除,视情况而定。甚至自定义HTTP方法。
这是用于处理在阿卡-HTTP HTTP请求方便DSL。检查阿卡-HTTP DOC here