Scala讲座:编程的思考方法

这篇是Scala讲座第七篇的第三部分,总括了函数式编程的思考方法。

在进行什么编程的时候,你用什么方法来思考呢?用命令是方法来考虑的话,一定是考虑“首先有一个变量,然后一边循环一边判断一下这样的条件,接着进行这种操作・・・”这样的操作步骤吧。

面向对象式方法来考虑时,一定是先考虑“程序中出现的这个对象里有什么东西(数据)呀?”,然后再给对象分配 “动作”(方法)吧。整体印象应该是,“对象”们互相分配好自己的工作,对象自己只做自己的工作其他的工作交给其他对象来完成,“对象”们互相合作来完成一个处理吧。即使是面向对象的情况下,对于一般语言来说,对象方法内也是用命令方式来实现的。

那么,函数式编程该是怎样的景象呢?函数式编程是“将函数应用在值或者对象上”这种思考方法,也就是函数只是将值或者对象转换成不同的别的东西。这样说,可能函数式方法还是很难在读者脑中浮现,那么就以“命令型”和“函数式”两种类型的例子为基础进行阐述吧。

[Scala讲座]题目:架子上的苹果

题目内容为模拟“架子上有100个苹果,一个个剥皮吃掉最后一个也没有了。“这个过程。运行结果的样子因该如下所示:

> scala AppleCounter  



99 apples on the wall.  




98 apples on the wall.  



:  



2 apples on the wall.  




1 apple on the wall.  



no apple on the wall. 
当苹果只有1或0个的时候,由于不是复数情况,所以处理方法有所不同。先用命令方式来实现一下。
object AppleCounter{  


def main(args:Array[String]):Unit = {  


var appleList:List[String] = List()  



for(i 1 to 100) {  




var counter = 100 -i  




if (counter == 1) appleList = appleList ::: List("1 apple on the wall.")  




if (counter == 0) appleList = appleList ::: List("no apple on the wall.")  




if (counter != 1 && counter != 0)  




appleList = appleList ::: List(counter + " apples on the wall.")  



}  


appleList.foreach(x => println(x))  


}  


} 
首先准备好列表变量appleList,接着做100次循环。循环中用变量counter来存放当前所剩的苹果数,并根据该数字向例表末尾加入描述文本,其中对于1个和0个的情况进行特殊处理。最后使用appleList的foreach方法对每一列表成员进行打印操作。题外话,由于Scala是函数式+面向对象语言,所以能够以这种命令式方法来编程,这对于不熟悉函数式编程的用户来说也还真不错。
好了,这次用函数式的方法来重新实现一下同样的逻辑。那么该怎样考虑函数式的实现呢?下面是实现例子。
object AppleCounter {  



def main(args:Array[String]):Unit = {val appleList = (0 until 100).reverse.map(x => x match {  




case 1 => "1 apple on the wall." 




case 0 => "no apple on the wall." 




case _ => x + " apples on the wall." 



})  


appleList.foreach(x => println(x))  


}  


} 
这里不是想说明“程序短了不少啊・・・”,而是希望大家明白思考方法的不同之处(不过这里并没有声明变量appleList的类型,能够进行如此复杂的类型推断也真是挺厉害的呀!)。编写这段程序的时候,我一开始就没有考虑到循环这个概念。比起循环,我考虑的是如何将函数用在数字列表变量上。首先不是逻辑,而是创建用于执行函数的对象(这里是数字列表),然后考虑选择哪种函数来执行。
首先考虑创建如下的列表对象。
List(99, 98, 97, .... 2, 1, 0) 
这个通过(0 until 100).reverse部分来实现。接着对于这个列表的一个个数字,考虑返回数字相对应字符串的函数。对应部分如下
(上面的列表).map(x => x match {  



case 1 => "1 apple on the wall." 




case 0 => "no apple on the wall." 




case _ => x + " apples on the wall." 



}) 
用Scala进行像样的函数式编程时,map是最重要的函数之一。也就是,对于列表中的每个元素用map函数传进来的函数执行一下,然后返回他的结果列表。这里传递给map函数的参数(函数对象)内容是:对于1返回1 apple on the wall.;对于0返回no apple on the wall;其他情况比如22,返回22 apples on the wall。根据该内容,map函数返回如下列表
List("99 apples on the wall.", "98 apples on the wall.", …"no apple on the wall.") 

最后一行类似于命令式编程,对于例表appleList用foreach方法循环遍历,并用foreach传进的函数打印列表所有的元素,然后程序结束。
函数map不仅在List类中有,其他很多类中也有。

Scala讲座:编程的思考方法

Scala讲座 图:map函数概念图

相关推荐