Contents
  1. 1. 循环
    1. 1.1. 范围for
    2. 1.2. 多循环
    3. 1.3. 集合的for
    4. 1.4. 带filter的循环
    5. 1.5. 带yield的for
    6. 1.6. 循环控制
  2. 2. 函数
    1. 2.1. 函数声明
    2. 2.2. 函数定义
    3. 2.3. 函数调用
    4. 2.4. call-by-name函数参数
    5. 2.5. 可变长参数
    6. 2.6. 函数参数默认值
    7. 2.7. 嵌套函数
    8. 2.8. 部分应用函数
    9. 2.9. 函数参数值按名称传递
    10. 2.10. 递归函数
    11. 2.11. 高阶函数 higher order function
    12. 2.12. 匿名函数
    13. 2.13. 柯里函数

循环

scala支持whiledo-while循环,与java差别最大的是for循环及中断循环的控制。

1
2
3
4
5
6
7
while(){
}
--------
do{
}while();

范围for

tountil两种,主要差别是后者不包括上界
此处的<-称为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
}
}

运行结果:

1
Returned Value : 9

嵌套函数

函数内可定义函数,内部定义的函数称为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)
}
}

运行结果:

1
2
3
4
1
1
2
6

部分应用函数

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() + "]"
}

输出为

1
[10]

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

调用方式

1
strcat("foo")("bar")

当然,函数链长度并不限于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!

Contents
  1. 1. 循环
    1. 1.1. 范围for
    2. 1.2. 多循环
    3. 1.3. 集合的for
    4. 1.4. 带filter的循环
    5. 1.5. 带yield的for
    6. 1.6. 循环控制
  2. 2. 函数
    1. 2.1. 函数声明
    2. 2.2. 函数定义
    3. 2.3. 函数调用
    4. 2.4. call-by-name函数参数
    5. 2.5. 可变长参数
    6. 2.6. 函数参数默认值
    7. 2.7. 嵌套函数
    8. 2.8. 部分应用函数
    9. 2.9. 函数参数值按名称传递
    10. 2.10. 递归函数
    11. 2.11. 高阶函数 higher order function
    12. 2.12. 匿名函数
    13. 2.13. 柯里函数