我刚开始学习Akka /
Scala,我写了一个小聊天服务器.
想象一下,这是一个基于房间的聊天服务器,每个人都可以创建自己的房间,可以同时在几个房间.每当房间里的房间用完时,房间就会关闭.房间由id:Int标识,并具有不可变的名称:String.我写了下面的代码来介绍房间.
class Room(val id: Int, val name: String, var host: ActorRef) extends Actor {
def receive = {
case GetId() =>
sender ! id
case GetName() =>
sender ! name
case AddMember(member) => ...
case RemoveMember(member) => ...
case BroadcastMessage(from, message) => ...
}
现在,客户需要所有房间的ID和名称,以决定加入哪个房间.
val rooms: List[ActorRef] // Obtained somewhere
val getIdFutures: List[Future[Int]] = rooms.map { (_ ? GetId()).mapTo[Int] }
val getNameFutures: List[Future[String]] = rooms.map { (_ ? GetName()).mapTo[String] }
val getIds: Future[List[Int]] = Future.sequence(getIdFutures)
val getNames: Future[List[String]] = Future.sequence(getNameFutures)
for (ids <- getIds; names <- getNames) yield {
ids zip names map { pair =>
val id = pair._1
val name = pair._2
println(s"$id: $name")
}
}
嗯,好吧,它的工作原理……但是……有没有办法让我更方便地访问Actor中的那些不可变成员?我试图为房间演员制作一个包装器,如下面的代码:
case class RoomWrapper(val id: Int, val name: String, actor: ActorRef)
看起来很好,但有一个问题:现在我必须到处传递RoomWrapper对象.如何在房间被毁时收到通知?我无法上下文.观看一个RoomWrapper!
怎么解决这个?我有可能这样写吗?
val rooms: List[ActorRef]
rooms map { room =>
println(room.id)
println(room.name)
}
最佳答案 嗯,这只是我的意见.我不认为你应该按照你的建议去做,因为那样会使你的代码“多样化”(我的意思是,从演员模型中变成更具体的东西).从技术上讲,演员不应该共享任何州,而且他们应该只对事件(消息)做出反应.无论如何,使用for comprehension可以将上面的内容重写为:
for {
room <- rooms
id <- (room ? GetId).mapTo[Int]
name <- (room ? GetName).mapTo[String]
} {
println(id)
println(name)
}
此外,您可以创建一条消息,将id和name作为元组返回,依此类推.可能性是无限的,但我不允许以这种方式直接访问甚至是不可变状态,因为它使我对编码进入应用程序的特定模式的视觉有点混乱.