Scala函数进阶
Scala函数的最基本结构如下:
def funcName(arg1: type1, arg2, type2): ReturnType = {
//...
}
result = funcName(value1, value2)
那么,scala的函数又有哪些高级的用法呢?
其他语言常见用法
这些用法在C、Java、Python等语言中也会经常见到,不过语法格式可能有些许不同,故一起说明
指定参数名称
可以指定传入值是哪一个参数,此时参数顺序不一定要与定义一致
def add(a: Int, b: Int): Int = a+b
result = add(b=1, a=2)
可变参数
Scala允许你的函数参数中,最后一个参数设置为可变长度,即可传入任意多个参数
def func(arg1: Int, arg2: String*): Unit = {
println(arg1)
for (s <- arg2) println(s)
}
func(1, "ab", "cd")
默认参数值
Scala允许你的函数参数有默认值,但当你调用函数不指定参数时,缺省只能从后往前
def func(arg1: Int = 1, arg2: Int = 2): Int = arg1 + arg2
result = func()
匿名函数
Scala允许你定义一个不指定名称的函数并声明为一个变量,语法上比lambda更简洁一些
var func = (x: Int) => x+1
a = func(2)
模板函数
Scala允许你函数中的一些数据类型是未定的,语法上也很简单
def func[T](arg: T): T = {
// ...
}
这里的模板T,可以当你调用func时指定具体的class。
Call-by-Name与Call-by-Value
当我们向函数中传入一个函数调用时,一般而言我们是打算将该函数返回值作为参数传入,这样的被称为Call-by-Value。不过有些时候,我们可能希望传入的函数其返回值的计算是在函数内部使用这一参数时,而不是函数传入时,这样的被称为Call-by-Name。当然,我们完全可以通过传入函数的引用,从而在内部调用函数来达到这一目的。但也会有一些特殊情况,比如这个函数的参数我不希望被调用函数获取之类的,这时便要使用Call-by-Name的机制。实现上很简单,参数声明改为
count = 5
def gen(): Int = {
count -= 1
return count
}
def func(funcResult: => Type): ReturnType = {
for (i <- 0 to 4) print(gen())
}
这样,funcResult的函数返回值,仅当在内部使用该参数时被调用,且每当被使用时该函数都会重新执行。也就是说,上面一个例子,执行func(gen())后输出的是43210。
Partial Applied Function
注意要区别Patial Function与Partial Applied Function,前者是一个数学概念,指函数的定义域中某些值在值域没有映射。而我们说的后者,其实有一些像闭包,不过是在给定函数后我们再去进行了修改,用以减少传入函数的参数,如
def add(a: Int, b: Int): Int = a + b
val adder = add(1, _: Int)
adder(2) //3
看这个例子是不是就明白了呢?当然对于多参数情况,你可以指定其中任意几个参数的值,位置不定。
Currying
还是上面那个加法函数,不过我们换一个方法定义
def add(a: Int)(b: Int) = a + b
如果你还是每次传入对应数量参数,那么这个函数跟上一个没有区别。但如果你只传入一个,那么其返回值将是类似上一个例子中类似adder的函数引用。
总结
Scala支持了很多cool的用法,它们被创造了出来,自然说明其有适宜的业务场景。但对于一般情况,普通的定义已经足以支撑应用时就避免去用一些复杂的方法,这样就只是炫技罢了,还增大了维护难度。