scala 摘记(二)

future

有了类似 Option/Try 这种经历之后,理解 Future 其实是一个类似的事情,只是 Try 的结果是在当前 thread 里面获得的,而 Future 是通过一个 context(如 thread pool)并行的获得的。因此 map/flatMap 和 for comprehension 都是可以用到的,特别是简单的几个 future 之间的关系通过 for comprehension 可以比较容易的组合起来。通过 future 的 composition 我们最终获得的那个 future 通过 callback 就能影响到最后的事情,比如响应一个 service call,可以通过一个 thread pool 将 ABC 几个事情分派出去,然后在获得的 Future 里面通过 onComplete 将 Success/Failure 返回到 client 侧。参看这里

higher-order functions

所谓的 higher-order function 即类似“算子/泛函”的概念,定义域和/或值域是函数,例子很多,除了 map/filter 以外还有做 composition 的 compose 和 andThen。对于 partial function 来说可以通过 lift 将其 lift 成为 function,这样返回的是 Option 了。

常见的技巧是某些函数通过 curried 就能返回函数了。partial application 除了对一般函数通过 _ 类似 boost.bind 使用以外,curry function 是另一种常见的选择,与前面讨论 structural typing 类似的做法是可以通过 curried function 来接受实现类,从而避免使用 env variable。参见这里

type class

这个技巧就是前面讨论过的 C++ 的 traits 技巧,scala 里面通过 context view 来做,即将类型 T 隐式转换到对应的“traits(C++)”或者一个特殊的 generic type,Ops[T],这 trait(scala)实现了 T 所需要的所有操作和常数等,通过这个包含 T 领域知识的 Ops[T] 就可以建立一些更复杂的上层库,比如 Ops 表示的是一些数值运算基本操作,就可以为其提供对应的统计功能。为了避免写 [T](t: T) (implicit op: Ops[T]) 可以通过 context view,即 [T: Ops] (t: T)。

path-dependent type

这是一个比较奇特的语言特性,通常我们设计一个类/trait A 如果有一个依赖的“类型 B”(作为某个问题中间或者结果的表达),我们可以将其放在 companion object 里面,然后需要的时候构造它即可。但这样一来,任意 A 的对象都可以接受 B。scala 一个奇怪的特性是允许将 B 的定义直接放在 A 中,这样 A 的不同对象对应的 B 将是不同的类型,因此他们互相不能直接赋值或者传递到其他对象的方法里面。如果你希望定义一个这种方法,可以用诸如 (f: Foo) (b: f.Bar) 的形式来表达。

一个比较常见的用法是与 abstract type member 来联用。你可以定义一个抽象类,其中通过 abstract type members 表示这类使用的一些类型,那么在这个 pattern 下,为这个抽象类提供的方法接受抽象类对象,可以通过对象引用 path-dependent type,这就可以实现某些奇怪的 type safety。参看这里

actors

使用 actor 需要理解其运做机制,本质上和 Qt 之类的 GUI 类似,通过 dispatcher 将消息发送到对应的 actor 上,actor 运行的时候会与 thread binding 处理掉一条消息,因此 dispatcher 本身负责维护一(几)个 message queue,这是需要 blocking 的地方。书写 actor 的程序一般继承 akka.actor.Actor,使用 receive 方法接受 partial function:这是一个 design 上的 decision,现在 message 为 Any,因此需要通过 partial function 处理自己感兴趣的 message(据说有 experimental 的 typed channel);另外有一个 sender 作为 implicit 的参数,如果需要将消息发回去可以直接用这个;构造 Actor 需要使用 actor system,这样才会被关联到 dispatcher 上,但是返回的是 ActorRef 而不是实际的 actor,这是为了能够隔离实际的 actor,通过这个引用可以向 actor 发送消息(通过 !)或者要求一个 future(通过 ?,方便与基于 future 的 API 集成)。参看这里

处理异常一般需要理解 actor 的 tree 结构,你可以在一个 actor 里面通过其 context 产生子 actor,这样子 actor 一旦出错,可以在父 actor 中选择处理方法(stop/restart/resume/escalate),比较好的设计会把 actor 弄成 resume 和 restart 的那种分开成两个 actor,这样如果你希望保留一些状态可以放在 resume 的子 actor 里面。通过覆盖 actor 的 preStart、postStop、preRestart 和 postRestart 可以定制一些需要的行为。参看这里

后面的内容将看看这篇里面指出的几个东西。大概可以开始用 scala 写些小玩意玩玩了。

——————
And God hearkened unto Leah, and she conceived, and bare Jacob the fifth son.

Advertisements
scala 摘记(二)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s