Scala语法要点
Links
比较有用的链接收集如下。
官方的语法要点:http://docs.scala-lang.org/cheatsheets/
不错的教程:http://www.tutorialspoint.com/scala/
还可以但不太清楚:http://www.code123.cc/672.html
变量和函数的声明
Scala中比较奇怪的是变量和函数声明,譬如:
// 下面是两种变量,一种是普通变量,另外一种类似C++的引用
var v0 = 10
val v1 = 10
// 函数的声明,用的def关键字,但是也用等号
def f0(): Unit = {
println("this is a function")
}
Scala的函数返回值Unit是没有返回值的意思,参数也是类似UML格式,但是更重要的是和变量声明一样,用=来指名后面是函数体。
延迟求值
函数的参数可以延迟求值,譬如参数传进去是函数变量时,或者类型是函数变量时。
对于函数参数是变量的延迟求值,譬如:
// 延迟求值,参数可以是函数变量
def max(a: Int, b: Int): Int = {
if (a < b) return b else return a
}
println(t0(max(10, 11)))
// 下面的例子中,max会在t0中求值,而不是求值后把结果作为参数传进去,
// 也就是延迟求值,即call-by-name
def t0(v: => Int): Int = {
return v * 3;
}
// 下面的例子中,max会求值后再传给t0,即call-by-value
def t0(v: Int): Int = {
return v* 3
}
对于函数参数是函数变量时,即明确定义参数的函数原型时,譬如:
// 延迟求值,参数可以是函数变量,注意传参方式变了,三个参数了。
def max(a: Int, b: Int): Int = {
if (a < b) return b else return a
}
println(t0(max, 10, 11))
// 因为第一个参数是函数,所以必须要延迟求值,也就是必须call-by-name
// 注意使用参数v的方式也变了。
def t0(v: (Int, Int) => Int, a: Int, b: Int): Int = {
return v(a, b) * 3
}
函数参数
函数的参数只有一种形式,即def f(v: Type): Type = {}
,也就是说,所有的参数都是v: Type
,即名称和类型。
但是有几种不同的情况,譬如:
v: Int
,这种就是普通参数,call-by-value,预先求值的。v: => Int
,这种就是普通参数,call-by-value,延迟求值的。可以把=> Int
看做是类型,这种类型就说明是延迟求值。v: (Int) => Int
,这种就是参数类型是函数,必须是call-by-value。这个时候函数的返回值肯定就是参数的值,那么它们的类型也就是一样了。可以认为原本是v: (Int): Int => Int
(注意这样是有语法问题的),其中(Int): Int
就是函数的类型,两个参数一样就省略返回值,简写成v: (Int) => Int
。
匿名函数
匿名函数是声明函数时没有指定函数名称,譬如传递给函数时作为参数,或者赋值给变量时。
声明匿名函数的方式和函数是不一样的,不用def,不用=定义,不包含返回值,而是用=>指定body。也就是匿名函数的声明语法是特定的,不同于函数,譬如:
(x: Int) => {
// function body, param is x
}
匿名函数作为函数参数,譬如:
def t0(v: (Int, Int) => Int, a: Int, b: Int): Int = {
return v(a, b)
}
def anonyFunc(): Int = {
t0((a: Int, b: Int) => {
println("anonymous function, a=" + a + ", b=" + b)
return a+b
}, 10, 11)
}
或者作为函数变量的用法:
def anonyFunc2(): Unit = {
val f = (a: Int, b: Int) => {
println("anonymous function as variable, a+b=" + (a+b))
return a+b
}
f(10, 11)
}
因此,closure和high order function等都很好理解了。
总结
综合上面的语法原则,各种组合就很明确了。
譬如有个帖子讨论下面两个函数定义的差别:
// http://scalagroup.group.iteye.com/group/topic/26303
def test(code: => Unit){ code }
def test1(code: () => Unit){ code }
分析这个代码,test和test1都是两个函数,区别在于参数不一样。
code: => Unit
,类似于code: Unit
即没有类型,但是=> Unit
表明这个是call-by-name的,即延迟赋值。code: () => Unit
,这个参数类型是函数():Unit
,返回值和参数类型一样是Unit,也就是这个函数参数为空返回值为空。另外,因为是函数参数所以必须是call-by-name的。
再看另外一个教程的例子:
// http://www.tutorialspoint.com/scala/scala_closures.htm
val multiplier = (i:Int) => i * 10
分析这个代码,这个是个变量定义,右边是个匿名函数,也就是它是这么写的:
val multiplier = (i: Int) => {
return i * 10
}
这个就比较清楚了,multipler就是个函数变量,一个整型参数,返回值推导出来也是个整型的。所以使用时应该multiplier(10)
结果是100
。