Actors in Scala(Scala中的Actor)(预打印版) 第四章 Actor Chat (A)
张贵宾
2011.10.21
注:翻译这些英文书籍资料纯属个人爱好,如有不恰当之处敬请指正。
前面的章节展示了actor在消息传输方面的编程模型。不用惊奇,许多Scala的actor库定义了大量的处理发送消息和接收消息的编程结构。这些结构以内部领域语言(internal domain-specific language--DSL)的形式展现给了大家。本章将使用一个典型的消息应用程序:聊天程序,来向大家展示Scala的actor DSL的关键要素。
聊天程序允许用户通过对不同的主题交换消息来相互交互,每个主题代表一个聊天室,用户如果对一个聊天室主题下面的一系列讨论感兴趣的话,他便会订阅这个聊天室主题。一旦订阅了,用户可以给聊天室发送消息,反过来,他也能收到聊天室中其他订阅者发送的消息。图4.1提供了本章开发的聊天程序的概览。
case class User(name: String) case class Subscribe(user: User) case class Post(msg: String) case class UserPost(user: User, post: Post)
在actor中所有的消息处理发生在 actor 方法内,下面的代码展示了如何定义actor:
import scala.actors.Actor class ChatRoom extends Actor { def actor() { // the actor's behavior } }
val chatRoom = new ChatRoom chatRoom.start
class ChatRoom extends Actor { def act() { while(true) { receive { case Subscribe(user) => //处理订阅 case Unsubscribe(user) =>//处理取消订阅 case UserPost(user, post) => //处理发帖 } } } }
在这个例子中,ChatRoom期望收到Subscribe、Unsubscribe或者UserPost消息,当收到这三种消息时,ChatRoom将会评估模式箭头=>右边的表达式。
Scala的actor库也提供了一种快捷方式来定义和启动actor,只需要一步即可,而不需要显示的扩展Actor trait。下面的代码展示了使用简化写法的actor。
val chatRoom = actor{ while(true) { receive { case Subscribe(user) => //处理订阅 case Unsubscribe(user) =>//处理取消订阅 case UserPost(user, post) => //处理发帖 } } }
收到了Subscribe消息之后,ChatRoom必须把用户添加到它的订阅者列表中。首先,看起来可以在一个list中保存聊天室的订阅者,但是要注意订阅者必须能够接受来自聊天室的消息。在我们当前的设计中,当UserPost消息到达时,ChatRoom会遍历所有的订阅者,并且把消息内容发给除了发送消息者之外的所有的订阅者。
因此用户可以接受来自聊天室的消息,在订阅会话中,我们可以用actor来代表一个用户,当ChatRoom收到了Subscribe消息,它可以创建一个新的actor来代表用户,把用户和新创建的actor关联。这个actor,反过来将要处理ChatRoom发给它的Post消息,代码如下所示:
val chatRoom = new ChatRoom chatRoom ! Subscribe(User("Bob")) var session = Map.empty[User, Actor] while(true) { receive { case Subscribe(user) => val sessionUser = actor { while(true) { self.receive { case Post(msg) => //Send the message to sender } } } session = session + (user -> sessionUser) //TODO handle the Unsubscribe message } }