Kestrel.scala中的QueueCollection

开发 后端
本文介绍了Scala中的QueueCollection。这是一个Scala的比较特殊语法。文章中还包括了HashMap的创建方法。

有关Kestrel的Scala实例已经介绍到了第三篇,接下来介绍Scala中的一个走读分支:QueueCollection。

在Kestrel.scala的startup方法中,告诉我们接下来有两个走读的分支,一个是QueueCollection和PersistentQueue。另一个是KestrelHandle。KestrelHandle是和NioSocketAcceptor相联系的,所以可以想想KetrelHandle是用来处理链接……与之相关的还有memcache目录下的Codec.scala。

我们先忽略Kestrel.scala在startup中的几个语法细节,从相对比较简单的QueueCollection开始吧:

  1. class QueueCollection(queueFolder: String, private var queueConfigs: ConfigMap) {  
  2.   ……  
  3.   if (! path.isDirectory) {  
  4.     path.mkdirs()  
  5.   }  
  6.   ……  
  7. }  

这是一个Scala的比较特殊语法。class本身就是一个建构函数。程序中queueFolder和queueConfigs是创建是必须的两个参数。class在Scala里面就支持一种建构函数。这里的参数也可以看做是整个class的变量,所以程序中的private只表示在类以外的地方,没有办法获取queueConfigs这个参数。

接下来是关于HashMap的创建:

  1. private val queues = new mutable.HashMap[String, PersistentQueue]  
  2.  

我们知道HashMap是有两个类型,一个是键的类型,一个是值的类型。在queues里面,String就是键,PersistentQueue就是值。这跟Java/C++的模板累死,不需要特别的解释了。

然后是一个很多地方都用到的Count,在Count.scala里面有说明,就是一个统计技术的类,写法很干净,注意里面的函数定义,都没有用大括号。多看几遍就熟悉,Scala是怎么定义函数的了。显然,这看起来更像是命令,而不是函数体的声明。

经过两段比较好理解的代码之后,出现了一段恐怖的代码:

  1. queueConfigs.subscribe { c =>  
  2.   synchronized {  
  3.     queueConfigs = c.getOrElse(new Config)  
  4.   }  
  5. }  

如果只是看这段代码,就有种喉咙被卡住,咽不下去又吐不出来的感觉。这段代码做了些什么,大家都能猜出来,郁闷的是,这到底遵循的是那个语法规范呢?咋代码就写得那么四不像呢?不过如果我们回过来看一下net.lag.configgy.configMap中subscribe的定义,似乎就能明白多一点:

  1. def subscribe(f: (Option[ConfigMap]) => Unit): SubscriptionKey = {  
  2.   subscribe(new Subscriber {  
  3.     def validate(current: Option[ConfigMap], replacement: Option[ConfigMap]): Unit = { }  
  4.     def commit(current: Option[ConfigMap], replacement: Option[ConfigMap]): Unit = {  
  5.       f(replacement)  
  6.     }  
  7.   })  
  8. }  
  9.  

看来还是有点难度——呃,其实这是Kestrel的一个非常灵活的功能,定义作为参数的函数的类型:

  1. func_name : (param_type1, param_type2) => Unit  

func_name是一个有两个参数的函数,参数类型分别是param_type1和param_type2。所以subscribe的参数是一个有一个参数的函数,这个参数所以Option[ConfigMap]。关于Option, Some的话题,我们稍后再谈。这已经不影响程序的阅读了。

回到在QueueCollection.scala的代码,当我们知道subscribe的参数是一个函数的时候,下面这段代码的作用就是,当queueConfigs的某些状态变化的时候,会调用一个叫commit的内部函数,而这个内部函数的功能,就是把新替换的配置,作为参数c,传递给这段代码,结果是queueConfigs = c.getOrElse(new Config)。涵义是,如果不存在就添一个缺省值。

  1. queueConfigs.subscribe { c =>  
  2.   synchronized {  
  3.     queueConfigs = c.getOrElse(new Config)  
  4.   }  
  5. }  

绕了一圈,其实是定义了一个触发器,并且触发器的作用是,当设置是空置的时候,补上一个标准的缺省值。完全是杀鸡用了牛刀。但是回过来我们重新考虑Scala对架构上的意义,这种把函数作为参数的做法,可以很方便的实现callback操作,当然这需要配合上object这样的类,否则寻找对应的callback类,还需要费点周章。

随后,我们看到了著名的闭包(closure),而且一来还来了两段,第一段是filter,对于所有的成员“name”,如果 => 后面的内容返回是成功的话(如果name不包含~~),就添加到list里面去。

  1. def loadQueues() {  
  2.   path.list() filter { name => !(name contains "~~") } map { queue(_) }  
  3. }  
  4.  

第二段是把list变成一个map,完整的写法应该是

  1. map { _ => queue(_) }  
  2.  

很多时候不需要写成那么麻烦,可以直接把 _ => 给省略了。有时候因为习惯的原因,你会猜想queue又是一个什么特殊的语法?其实它一点都不特殊,往下大概10行左右,就是它的定义。queue,是把一个字符串的队列名,转变成一个真正的PersistentQueue的函数。所以load_queues,在大体上起了初始化队列的作用。

后面的段落中还有一个使用了closure的语法:

  1. def currentItems = queues.values.foldLeft(0L) { _ + _.length }  
  2.  

查询一下foldLeft的函数说明如下:

  1. def  foldLeft[B](z : B)(op : (B, A) => B) : B  
  2.  

根据函数的定义,foldLeft的函数,就是用迭代的方法,把所有元素的 length,也就是 _.length 累加起来,最后返回。_.length的总数。我们从语法上不难发现,{_ + _.length} 可以看做是 { a , b => a + b.length }。

读到这里,暂时告一段落。后半段QueueCollection还有一个重要的Scala语法——case下一次再讨论吧。

【编辑推荐】

  1. 走读Kestrel,了解Scala
  2. 从Kestrel看Scala的核心程序模块
  3. Scala实例教程:Kestrel
  4. 从Scala看canEqual与正确的的equals实现
  5. Scala编程语言
责任编辑:yangsai 来源: dingsding
相关推荐

2009-09-22 10:15:42

PersistentQScala

2009-09-28 11:25:17

PersistentQKestrelScala

2009-09-28 11:37:03

Journal.scaKestrel

2009-09-18 11:44:05

Scala实例教程Kestrel

2009-09-28 11:42:21

KestrelScala

2009-09-28 10:26:12

Scala代码实例Kestrel

2009-09-22 09:42:24

Scala的核心

2009-07-22 07:45:00

Scala代码重复

2009-07-22 07:53:00

Scala扩展类

2009-07-08 15:35:18

Case类Scala

2023-06-12 15:33:52

Scalafor循环语句

2009-07-21 17:21:57

Scala定义函数

2009-07-08 12:43:59

Scala ServlScala语言

2010-09-14 15:34:41

Scala

2020-10-31 17:33:18

Scala语言函数

2009-07-22 08:57:49

Scalafinal

2009-07-21 11:25:03

ScalaRational类

2009-07-20 18:03:26

Scala程序Singleton对象

2017-03-07 15:13:28

Scala偏函数函数

2009-11-16 17:04:46

Inside Scal
点赞
收藏

51CTO技术栈公众号