循环
scala支持while
和do-while
循环,与java差别最大的是for
循环及中断循环的控制。
1 2 3 4 5 6 7
| while(){ } -------- do{ }while();
|
范围for
有to
和until
两种,主要差别是后者不包括上界
此处的<-
称为generator
,因为它在每次循环中产生值。
1 2 3 4 5 6 7
| for(i <- 1 to 10){ }// 将循环1,2,3...10,共10次 ----- for(i <- 1 until 10){ }// 将循环1,2,3...9,共9次
|
多循环
可以在for
中使用;
分隔条件实现多循环,循环条件将从后往前开始计算
1 2 3 4
| for( a <- 1 to 3; b <- 1 to 3){ println( "Value of a: " + a ); println( "Value of b: " + b ); }
|
部分输出
1 2 3 4 5 6 7 8 9 10
| Value of a: 1 Value of b: 1 Value of a: 1 Value of b: 2 Value of a: 1 Value of b: 3 Value of a: 2 Value of b: 1 Value of a: 2 Value of b: 2
|
集合的for
1 2 3
| for( var x <- List ){ statement(s); }
|
带filter的循环
1 2 3 4 5
| for( var x <- List if condition1; if condition2... ){ statement(s); }
|
如
1 2 3 4 5 6
| val numList = List(1,2,3,4,5,6,7,8,9,10); // for loop execution with multiple filters for( a <- numList if a != 3; if a < 8 ){ println( "Value of a: " + a ); }
|
带yield的for
你可以将for
循环的返回值存储在变量中或者通过函数返回,这需要在循环体后加yield
关键字。
1 2 3
| var retVal = for{ var x <- List if condition1; if condition2... }yield x
|
如
1 2 3 4 5 6 7
| var retVal = for{ a <- numList if a != 3; if a < 8 }yield a // Now print returned values using another loop. for( a <- retVal){ println( "Value of a: " + a ); }
|
retVal是一个集合,其元素为1,2,4,5,6,7
循环控制
scala并没有java中的break
,continue
关键字。但从2.8开始加入了中断控制。
1 2 3 4 5 6 7 8
| import scala.util.control._ val loop = new Breaks; loop.breakable{ for(...){ loop.break; } }
|
首先须导入scala.util.control
包,并new
出一个Breaks
对象,将循环置于obj.breakable
后的花括号中,然后在循环内就可以使用obj.break
中断循环。
如果有多层循环,可以new
多个实例,从而方便地实现从内层循环直接跳出。
函数
函数与方法的叫法,经常混用不分,但也有细微差别,方法是对象的一部分,有名称、签名和可选的annotation,而函数本身就是对象,可被赋值给变量。或者说定义为某对象一部分的函数则为方法。
函数可在源文件的任何位置声明,并且可以嵌套,也就是函数中定义函数。另外scala的函数名可以包含运算符。
函数声明
1
| def functionName ([list of parameters]) : [return type]
|
如果没有等号=
和函数体,那么就是抽象函数
函数定义
1 2 3 4
| def functionName ([list of parameters]) : [return type] = { function body return [expr] }
|
如果一个方法不需返回值,可以将其声明为返回Unit
类型,等效于java中的void
类型,无返回值的函数称为procedures
.
语法
1 2 3 4 5
| object Hello{ def printMe( ) : Unit = { println("Hello, Scala!") } }
|
函数调用
scala提供多种调用函数的语法。函数是scala
语言的核心,这也是为何scala被称为`函数式编程语言
,接下来将介绍一些重要的概念,每一个scala程序员都应该认真理解。
call-by-name函数参数
函数参数在传递之前其值已经决定,如果想参数的值在第一次调用时取值,可以使用call by name
参数
call by name
机制将代码块
(如下例中的函数名
)传递给函数参数,每次函数访问该参数时都会执行该代码块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| object Demo { def main(args: Array[String]) { delayed(time()); } def time() = { println("Getting time in nano seconds") System.nanoTime } def delayed(t: => Long) = { println("In delayed method") println("Param: " + t) } }
|
输出如下
1 2 3
| In delayed method Getting time in nano seconds Param: 63999108438481
|
可变长参数
scala允许最后一个参数同类型重复,如下例中的String*
,实质是Array[String]
.
1 2 3 4 5 6 7 8 9 10 11 12 13
| object Demo { def main(args: Array[String]) { printStrings("Hello", "Scala", "Python") } def printStrings(args: String*) = { var i: Int = 0 for (arg <- args) { println("Arg value[" + i + "] = " + arg) i = i + 1 } } }
|
编译后运行
1 2 3
| Arg value[0] = Hello Arg value[1] = Scala Arg value[2] = Python
|
函数参数默认值
scala允许为函数(部分)参数指定默认值,有默认值的参数在调用时可以(部分)不赋值而使用默认值。
1 2 3 4 5 6 7 8 9 10 11
| object Demo { def main(args: Array[String]) { println("Returned Value : " + addInt(1, b = 3)) } def addInt(c: Int, a: Int = 5, b: Int = 7): Int = { var sum: Int = 0 sum = a + b + c return sum } }
|
运行结果:
嵌套函数
函数内可定义函数,内部定义的函数称为local function
本地函数
,其作用域也只在其封装函数内。
比如以下阶乘的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| object Demo { def main(args: Array[String]) { println(factorial(0)) println(factorial(1)) println(factorial(2)) println(factorial(3)) } def factorial(i: Int): Int = { def fact(i: Int, accumulator: Int): Int = { if (i <= 1) accumulator else fact(i - 1, i * accumulator) } fact(i, 1) } }
|
运行结果:
部分应用函数
scala允许你分几次给函数的参数赋值,这适用于某些参数已经确定,而剩余参数选定的情形。
将未确定值的参数赋值为下划线_
(数据类型不能省略),并将其结果保存在变量中,即得到部分应用函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.util.Date object Demo { def main(args: Array[String]) { val date = new Date val logWithDateBound = log(date, _: String) logWithDateBound("message1") Thread.sleep(1000) logWithDateBound("message2") Thread.sleep(1000) logWithDateBound("message3") } def log(date: Date, message: String) = { println(date + "----" + message) } }
|
函数参数值按名称传递
按名称传递允许你以任意顺序传递参数值。
1 2 3 4 5 6 7 8 9 10
| object Demo { def main(args: Array[String]) { printInt(b = 5, a = 7) } def printInt(a: Int, b: Int) = { println("Value of a : " + a) println("Value of b : " + b) } }
|
递归函数
递归在函数式编程中至关重要,scala对递归有良好的支持。
比如以下的阶乘实现。
1 2 3 4 5 6 7 8 9 10 11 12 13
| object Demo { def main(args: Array[String]) { for (i <- 10 to 20) printf("factorial of %d is: %d、民", i, factorial(i)) } def factorial(n: BigInt): BigInt = { if (n <= 1) 1 else n * factorial(n - 1) } }
|
结果
1 2 3 4 5 6 7 8 9 10 11
| factorial of 10 is: 3628800 factorial of 11 is: 39916800 factorial of 12 is: 479001600 factorial of 13 is: 6227020800 factorial of 14 is: 87178291200 factorial of 15 is: 1307674368000 factorial of 16 is: 20922789888000 factorial of 17 is: 355687428096000 factorial of 18 is: 6402373705728000 factorial of 19 is: 121645100408832000 factorial of 20 is: 2432902008176640000
|
高阶函数 higher order function
所谓高阶函数,就是以其它函数为参数,或者返回值为函数。
以下例子中apply()
接受 函数 f
和值v
为参数,并将v
传递给f
。
1 2 3 4 5 6 7 8 9
| object Demo { def main(args: Array[String]) { println(apply(layout, 10)) } def apply(f: Int => String, v: Int) = f(v) def layout[A](x: A) = "[" + x.toString() + "]" }
|
输出为
Int => String
表示f的数据类型为此参数列表与返回值的函数,layout是一个使用了模板的函数。
匿名函数
scala为匿名函数提供轻量级的语法支持,在源文件中,匿名函数也叫做function literal
(个人译为字面量函数
),在运行时,函数实例化,称为函数值
(注意此外不同于函数返回值)。
scala支持first-class
函数/头等函数
,意味着函数可用函数字面量
来表达并以对象形式呈现,亦即函数值
。
以下都是匿名函数
1 2
| var mul = (x: Int, y: Int) => x*y var userDir = () => { System.getProperty("user.dir") }
|
调用匿名函数
1 2
| println( userDir() ) //将输出当前目录
|
柯里函数
柯里化
将一个多参数函数转换为函数链
,每次接受一个参数。
1
| def strcat(s1: String)(s2: String) = s1 + s2
|
或者
1
| def strcat(s1: String) = (s2: String) => s1 + s2
|
调用方式
当然,函数链长度并不限于2
1 2 3 4 5 6 7 8 9 10 11
| object Demo { def main(args: Array[String]) { val str1: String = "Hello, " val str2: String = "Scala!" println("str1 + str2 = " + strcat(str1)(str2)) } def strcat(s1: String)(s2: String) = { s1 + s2 } }
|
输出
1
| str1 + str2 = Hello, Scala!
|