Scala:用传名参数构建并理解循环结构

简介:

 Scala 中允许无参数的函数作为另一函数的参数传递进去,也就是传名参数(call-by-name)。函数在 Scala 中是第一类公民(first-class citizen),其实函数也是一种特殊的对象,既然实质上是对象,当然也就能够作为另一个函数的参数传递进去了。 

传名参数也可以简单理解为不含参数的函数被传递给另一个参数。或许你可以看看我的另一篇相关文章:Scala:用传名参数实现断言机制及其特点 

 

我们可以用传名参数以及尾递归来实现一个很熟悉的语法结构 while 循环,代码如下面的 myWhile 函数: 

def myWhile(cond: => Boolean)(body: => Unit): Unit = {

      if(cond){

             body      // 方法体内必须包含循环条件的修改

             myWhile(cond)(body)

      }

} 

var num = 10

myWhile(num > 0){

      println(num)

      num -= 1       // 此句修改循环的条件

} 

注意我们在上面的myWhile 函数中的 body 必须含有驱使循环趋向结束的语句,即函数体中包含修改 cond 条件的语句。否则,在myWhile(cond)(body) 中则可能会出现每次if(cond) 都为 true 的情况,那就成了毫无用处的死循环了。 

myWhile 中有两个参数列表(使用了 Curring 技巧),都是传名参数的形式,即“名称:=> Unit”的格式,本来无参的函数我们也可以写成“名称:( ) => Unit”的格式,但是这两者在调用发是有所不同的,请看Scala:用传名参数实现断言机制及其特点 中的前面部分。 

前面说了 Scala 中的函数也是对象,那么传名参数所对应传递进来的无参函数也将被 Scala 编译器构建成一个对象。得特别注意的是,传名参数(无参函数)在传入另一函数直到在函数体中被具体调用前,是不会被计算的。这也可以看一下Scala:用传名参数实现断言机制及其特点 中后面部分的一点点解释。 

我们都很熟悉其他编程语言中的 while 循环结构,但是具体它们是不是被设计成尾递归的形式得以实现的,我也不清楚。不过书上说 Scala 中的尾递归调用会被 Scala 编译器优化成实际跟常见的 while 循环。因此,我觉得其他语言中的 while 循环结构应该不是用上面这种方法实现的。 

觉得 Scala 中这种可以构建自己所需的语言结构确实挺有趣,也比较启发习惯于命令式编程的我。呵呵

 

同样,既然可以类似的实现 while 循环结构,我们也可以实现 do-while 循环,代码如下: 

class DoWhile(body: => Unit){

      // 相当于do-while中的while

      def doWhile(cond: => Boolean){

             body

             if(!cond) doWhile(cond)  // 都传入cond且真值刚好相反

      }

}

 

// 相当于do,返回DoWhile类实例

def myDo(body: => Unit): DoWhile = new DoWhile(body)

 

// 测试

var num = 10

myDo{

      print(num + "  ")

      num -= 1

doWhile(num == 0)      //myDo返回DoWhile实例,再调用其doWhile函数 

 

在上面这个例子中,之所以要设计出一个DoWhile 类,并且定义了myDo函数的返回类型为DoWhile 类实例,是为了让返回的DoWhile 类实例直接调用其doWhile 函数。这样一来,就非常类似于常见的 do-while 循环结构了。 

同样,myDo 函数中 body 也必须且将会修改 cond 以使循环趋向结束。此外还应该注意if(!cond) doWhile(cond) 一句中判断是否继续调用doWhile 函数与传入doWhile 函数的 cond 是刚好相反的。



本文转自 xxxx66yyyy 51CTO博客,原文链接:http://blog.51cto.com/haolloyin/388232,如需转载请自行联系原作者

相关文章
|
Scala C语言
Scala的传值调用与传名调用理解
Scala的传值调用与传名调用理解
|
Java Scala
Scala教程之:scala的参数
Scala教程之:scala的参数
|
Java Scala
scala 学习笔记(03) 参数缺省值、不定个数参数、类的属性(Property)、泛型初步
继续学习,这一篇主要是通过scala来吐槽java的,同样是jvm上的语言,差距咋就这么大呢? 作为一个有.NET开发经验的程序员,当初刚接触java时,相信很多人对java语言有以下不爽(只列了极小一部分): 1. 一堆的setter/getter方法,没有c#中的property属性概念 2. 方法的参数值,不能设置缺省值 3. 不定个数参数的写法太单一 ... 然后java的拥护者讲出一堆大道理,说这样设计是如何如何有道理,各种洗脑,时间长了,也就被迫习惯了。
1292 0
|
1月前
|
分布式计算 大数据 Java
大数据-87 Spark 集群 案例学习 Spark Scala 案例 手写计算圆周率、计算共同好友
大数据-87 Spark 集群 案例学习 Spark Scala 案例 手写计算圆周率、计算共同好友
50 5
|
1月前
|
分布式计算 关系型数据库 MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
50 3
|
1月前
|
消息中间件 分布式计算 NoSQL
大数据-104 Spark Streaming Kafka Offset Scala实现Redis管理Offset并更新
大数据-104 Spark Streaming Kafka Offset Scala实现Redis管理Offset并更新
42 0
|
1月前
|
消息中间件 存储 分布式计算
大数据-103 Spark Streaming Kafka Offset管理详解 Scala自定义Offset
大数据-103 Spark Streaming Kafka Offset管理详解 Scala自定义Offset
91 0
|
1月前
|
分布式计算 大数据 Java
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
26 1
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方