Scala By Example: 拍卖会
来源:互联网 发布:vue2.0数据绑定原理 编辑:程序博客网 时间:2024/05/16 00:37
Scala的最大亮点就是Erlang风格的actor处理机制。但是第二个示例就涉及到Actor令我始料未及。不过这本书在Scala官网上是属于“进阶示例”,所以出手有些快也在所难免。(如果看不懂这个例子,最好先读铅笔书《Scala程序设计》(我假设你懂Java,否则你就直接选Erlang了,不是吗。书非常薄,如果有闭包之类的经验的话,三天就能看个差不多)。
1: #!/bin/env scala
2: !#
3:
4: import scala.actors._
5: import Actor._
6: import java.util.Date
7:
8: // for each base class, there are a number of 'case classed' which define the
9: // format of marticular messages in the class
10: abstract class AuctionMessage
11: case class Offer(bid: Int, client: Actor) extends AuctionMessage
12: case class Inquire(client: Actor) extends AuctionMessage
13:
14: abstract class AuctionReply
15: case class Status(asked: Int, expire: Date) extends AuctionReply
16: case object BestOffer extends AuctionReply
17: case class BeatenOffer(maxBid: Int) extends AuctionReply
18: case class AuctionConcluded(seller: Actor, client: Actor) extends AuctionReply
19: case object AuctionFailed extends AuctionReply
20: case object AuctionOver extends AuctionReply
21:
22: class Auction(seller: Actor, minBid: Int, closing: Date) extends Actor {
23: val timeToShutdown = 3600
24: val bidIncrement = 10
25:
26: println("Auction Started!")
27: def act() {
28: var maxBid = minBid - bidIncrement
29: var maxBidder: Actor = null
30: var running = true
31: while(running) {
32: println("Auction is still on")
33: // the 'receiveWithin' method of class Actor takes as parameters a
34: // time span given in milliseconds and a function that process
35: // messages in the mailbox.
36: val timeout = closing.getTime() - new Date().getTime()
37: println("To be timeout in " + (timeout / 1000) + "s")
38: receiveWithin(timeout) {
39: case Offer(bid, client) =>
40: if(bid >= maxBid + bidIncrement) {
41: if(maxBid >= minBid) maxBidder ! BeatenOffer(bid)
42: maxBid = bid; maxBidder = client; client ! BestOffer
43: } else {
44: client ! BeatenOffer(maxBid)
45: }
46: case Inquire(client) => client ! BeatenOffer(maxBid)
47: // if no messages are received in the meantime, this pattern is
48: // triggered after the time span which is passed as argument to
49: // the enclosing receiveWithin method.
50: case TIMEOUT =>
51: if(maxBid >= minBid) {
52: val reply = AuctionConcluded(seller, maxBidder)
53: maxBidder ! reply
54: seller ! reply
55: } else {
56: seller ! AuctionFailed
57: }
58: receiveWithin(timeToShutdown) {
59: case Offer(_, client) => client ! AuctionOver
60: case TIMEOUT => running = false
61: }
62: }
63: }
64: }
65: }
66:
67: val seller = actor {
68: println("I'm the seller")
69: var running = true
70: while(running) {
71: println("Seller is still waiting...")
72: receiveWithin(5000) {
73: case AuctionConcluded(_, maxBidder) =>
74: println("Auction concluded! The max bidder is" + maxBidder)
75: running = false
76: case AuctionFailed =>
77: println("F**k, it failed again!")
78: running = false
79: case _ => println("Nothing happened")
80: }
81: }
82: }
83:
84: val date = new Date(new Date().getTime() + 20000)
85: val auction = new Auction(seller, 100, date)
86:
87: val bidder1 = actor {
88: auction ! Inquire(self) // notice: auction is not yet started
89: receiveWithin(1000) { case msg => println(msg) }
90: }
91:
92: auction.start()
93:
94: val bidder2 = actor {
95: auction ! Offer(120, self)
96: receiveWithin(1000) { case msg => println(msg) }
97: }
98:
99: val bidder3 = actor {
100: auction ! Offer(150, self)
101: receiveWithin(1000) { case msg => println(msg) }
102: }
103:
104: val bidder4 = actor {
105: auction ! Offer(120, self)
106: receiveWithin(1000) { case msg => println(msg) }
107: }
108:
109: receiveWithin(30000) { case _ => } // little trick:)
注意,在程序的一开始,我们看到两个什么也不做的抽象类和一堆派生的case类/对象,它们就是在Actor之间传递的消息。当然,也可以不定义这些类和对象,case同样可以接受元组形式的参数。注意,使用Scala的时候,你可以彻底忘掉Singleton(也许有人还在争论Singleton要不要做双重加锁呢),那几个用object声明的对象就是Scala中的单例对象。(有人曾经评价ruby这样的魔幻语言让许多经典模式都瞬时凌乱,我认为Groovy和Scala都是如此)
第二个重点则是act()的方法。尤其重要的是receiveWithin和TIMEOUT的配合使用。想想看,用JAVA来写的话你需要写多少行?
原书的代码只包含了类的定义,为了运行这些代码,我加了N多行。大家可以运行这个程序看看输出是什么样的顺序。体会一下Scala消息传递的“风格”。
最后需要指出的是最后一行代码。逻辑上这行代码什么都不做,但是由于所有Actor(包括auction, seller 和一群bidder)都在自己的进程里运行,所以当bidder4被创立之后,主进程就结束了(而此时拍卖会并没有结束)。因此,加上一行等待专用码还是有必要的。
PS. 虽然我以说一口华丽的中文为骄傲,但是当写代码的时候,输入中文永远令我纠结。今天我下定决心,以后在IDE里也好、VIM里也好,都用鸟语书写了。(嗯,顺便把练字放到我的日程里,想当年我的书法还是很漂亮的)
PS II. 虽然把Scala的语法大致过了遍,真正写程序的时候还是不熟练,所以我做了个练习项目,用主要Scala来写,不会的地方用Groovy和Java搭一把。结果Scala和Java相互调用没有问题,Groovy和Java相互调用也没有问题,放到一起就杯具了。Groovy可以调用Scala,但是混合编译的时候要先编译Groovy后编译Scala,否则就报错,至于反过来,完全没法混合编译(IDEA和gradle都一样),看来只有把不同的代码分别编译后才能相互调用了。
PS III. 一想到以后不用再输入synchronized就兴奋。
- Scala By Example: 拍卖会
- Scala By Example: 泛型
- 《Scala by Example》
- Scala By Example: 一等公民
- Scala by Example: 第一个例子
- Scala By Example: 表达式与函数
- Scala By Example: 表达式与函数 习题
- Scala By Example: 一等公民 习题
- Scala By Example: 类和对象
- Scala By Example: 类和对象 习题
- A simple Scala call-by-name example
- Scala By Example: Case 类与模式匹配
- Scala By Example: Case 类与模式匹配 习题
- Scala开发Example
- 正则表达式 by example
- JavaScript by Example
- Jini by Example
- JavaScript by Example
- HTTP 错误 401.3 - 未经授权:访问由于 ACL 对所请求资源的设置被拒绝。
- 学习笔记10—JAVA高级视频04_Applet
- 学习笔记11—JAVA高级视频02_IO输入与输出
- kick boll
- linux性能监控,很全面
- Scala By Example: 拍卖会
- 使用javascript来访问本地文件夹
- 用javascript 实现网页鼠标右键弹出菜单功能
- 技术->成功?
- 给 VS 2010 选一个好用的代码行数统计器
- 网络编辑基础:对HTTP协议的头信息详解
- 自动点击webbrowser 里的超连接
- 20110225@06:35
- php.ini 上传文件配置及安全配置