Scala dispatch示例

12

我是一名Java工程师,最近在慢慢学习Scala。我找到了一些使用Dispatch进行简单GET请求的示例代码:

val request = url("http://somesite.com")
val result = Http( request OK as.String)
问题是...我不太明白这里发生了什么。首先,Http是一个类还是一个方法?其次,传递给它的参数是什么意思?我以为我们可能正在传递三个参数,Scala允许我们省略逗号。但当我尝试添加逗号时,我得到了一个编译错误,所以那肯定不对。
我确定对于Scala熟练的人来说这很合理,但我还没有达到那个水平,这阻碍了我的进展。我已经尝试在网上寻找文档,但没有找到有用的信息。

哦,抱歉。这是我正在阅读的Scala for Java开发人员,但我也在网上看到了类似的例子;例如:http://stackoverflow.com/questions/21103553/scala-dispatch-simple-get-request,甚至在Dispatch网站上也有:http://dispatch.databinder.net/Dispatch.html。 - Dave Taubler
2个回答

26

这是一个(痛苦地)明确的版本,去掉了所有的语法糖:

import dispatch.{ Defaults, Http, Req, as, implyRequestHandlerTuple, url }
import scala.concurrent.Future

val request: Req = url.apply("http://somesite.com")

val result: Future[String] =
  Http.apply(
    implyRequestHandlerTuple(request).OK[String](as.String)
  )(Defaults.executor)

url 是一个单例对象,带有一个 apply 方法,返回一个 Req case 类的实例。同样是单例对象的 Http 也有一个 apply 方法。 Httpapply 方法接受两个参数列表——第一个接受一个 Req 参数,第二个接受执行上下文(您可以将其视为 Scala 版本的 Java 的 Executor)。

implyRequestHandlerTuple 是一个隐式方法。 Req 没有一个 OK 方法,但编译器知道 RequestHandlerTupleBuilder 类有这个方法(并且它需要适当的参数——在这种情况下是从 Response 到某种类型的函数),因此在原始版本中,它自动应用此方法来从 Req 进行转换。

最后,as 是一个包,其中包含一个 String 单例对象。该对象扩展了 Response => String(更多的是语法糖,表示 Function1[Response, String])。我们的 OK 方法正在寻找一个接受 Response 的函数,所以这里没问题。

最终得到的是一个 Future[String]。有很多其他地方可以阅读关于 futures 的内容,因此我不会在这里详细介绍,但简而言之,这个值可以是未满足的(即仍在等待结果),或者满足了失败(在网络错误等情况下),或者成功满足(在这种情况下,它将包含响应体)。


5
也许你比别人早了12秒,或者你知道应该省略哪些词语。这就是你的人文教育所发挥的作用。在我女儿开始写下一篇书面报告之前,我会让她阅读这个回答。我看到你使用了罗伯茨女士推荐的过渡词:“最后”,“最终”。加上打勾! - som-snytt

9

url 是一个返回 Req 对象的方法。因此,request 的类型为 Req

Http 是一个类及其伴生对象,拥有几个 apply 方法的重载。所以当你看到:

Http(request OK as.String)

它实际上是以下语法糖:

Http.apply(request OK as.String)

好的,那么在apply内部发生了什么?似乎在request上调用了一个名为OK的方法。但是在查看API文档时,您可能会注意到类型Req中没有这样的方法OK。然而,有一个名为RequestHandlerTupleBuilder的类,它确实有这样的方法。并且在dispatch包中定义了一个隐式转换:

implicit def implyRequestHandlerTuple(builder: Req) =
    new RequestHandlerTupleBuilder(builder)

这里发生的情况是,当调用request OK时,编译器看到request没有OK方法。因此,它会寻找可能的隐式方法,这些方法接受Req作为参数,并返回具有此类方法的类型。上面的方法是它找到的隐式方法,因此将Req隐式转换为RequestHandlerTupleBuilder。

现在让我们来看一下OK的签名:

<code>def OK [T](f: Response => T): (Request, OkFunctionHandler[T])
</code>

它接受一个函数作为参数。特别地,这个函数接受一个Response作为参数,并返回一些其他类型T。在这种情况下,这样的函数是as.String,它具有类型Response => String。然后,OK将返回一个由RequestOkFunctionHandler[T]组成的元组。
这告诉我我们正在调用的apply的重载是这个:
def apply[T](pair: (Request, AsyncHandler[T])): Future[T]

(OkFunctionHandler 扩展了 AsyncHandler)

将所有内容以类似Java的风格并带有类型注释,你会得到:

val request: Req = url("http://somesite.com")
val result: Future[String] = Http.apply(request.OK(as.String))

如果只使用显式调用,代码会更像:

val result: Future[String] = 
    Http.apply(implyRequestHandlerTuple(request).OK(as.String))

简而言之,只有一个参数传递给Http.apply,它只是使用点自由风格来调用其他方法。

哇,我觉得我比你快了12秒。我也喜欢你的答案,但你可以更清楚地表明 request OK as.String 被解析为 request.OK(as.String) - Travis Brown
很难比底部的说明更清楚了。但是 url 本质上是一个方法吗?如果ScalaDoc有一个“用例”,其中您单击 url 方法,它将带您转到具有 apply 的对象,那就没问题了。我希望 ScalaDoc 的工作人员没有看到这个。 - som-snytt
我忽略了url,因为提问者并没有真正询问它。现在我有一个非官方的衡量标准,需要多少个我才能组成一个@TravisBrown。 - Michael Zajac
为了缩小差距,给你加上一个+1。 :) - Travis Brown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接