函数赋值
Scala中的函数其地位与类、对象等价,是可以独立存在的。因此可以直接将函数赋值给变量。根据语法约定,函数赋值时在函数后面必须加上空格和下划线。
var data = "<html><h1class='detail'>proxy list</h1></html>"
// 定义函数,函数不依赖类与对象
def xpathSelect(data: String) {
println("xpathSelect: " + data)
} // 返回xpathSelect: (data: String)Unit
// 将函数赋值给变量
val xpfuc = xpathSelect _
// 返回xpfuc: String => Unit = <function>
// 直接通过变量名调用函数
xpfuc(data)
// 返回xpathSelect: <html><h1>proxylist</h1></html>
匿名函数
Scala中的函数也可以不命名,这类函数也称为匿名函数。跟许多现代语言比如Go非常类似,可以将定义的匿名函数赋值给变量,也可以将匿名函数传入其他函数中。Scala中定义匿名函数语法规则为:(参数名: 参数类型) => { 函数体 }。
val convertMsgFmt = (msg: String) => {
//此处通过=>定义匿名函数,打印消息内容
printf("Content: %s", msg)
} // convertMsgFmt: String => Unit =<function>
convertMsgFmt("Short Message forTest")
// Content: Short Message for Test
高阶函数
Scala中可以将函数作为入参传入其他函数。而这类接收函数作为入参的函数,一般称作高阶函数(Higher-order Function),形式如下:
def execute(func: (String) => Unit,args: String) {
// 第一个入参为函数,第二个为String
func(args) // 执行传入的函数
}
execute(convertMsgFmt, data)
高阶函数也可以将函数作为返回值:
def generateFunc(funcName: String) =(args: String) => {
println(funcName + ":" + args)
}
val g = generateFunc("g")
// 此处返回值即为函数,赋值给变量g
g("String")
高阶函数的类型推断
Scala支持参数的自动类型推断,不需要明确类型;对于单一参数的函数,可以省略小括号;对于单一参数且在函数体中只使用一次的,则可以将接收参数省略并用”_”符号来替代。
def execute(func: (String) => Unit,args: String) { func(args) }
execute((args: String) =>println("args:" + args), "method1")
// 此行省略参数类型,由编译器自动推断
execute((args) =>println("args:" + args), "method2")
// 此行简化匿名函数形式
execute(args =>println("args:" + args), "method3")
def triple(func: (Int) => Int) = {func(9) }
triple(9 * _) // 此行用”_”符号代替入参
常用高阶函数
map函数:对传入的每个元素都进行映射并返回处理后的结果。
Array(2, 3, 5, 8, 13).map(7 * _)
foreach函数:对传入的每个元素进行遍历(无返回值)。
(5 to 10).map("*" *_).foreach(println _)
filter函数:对传入的每个元素作过滤,如条件判断为true则保留该元素,否则过滤掉。
(11 to 99).filter(_ % 3 == 0)
reduceLeft函数:从集合左侧元素开始执行reduce操作,即先对元素1和元素2进行处理,然后将结果与元素3处理,再将结果与元素4处理,依次类推。
(3 to 6).reduceLeft( _ * _)
// 这个操作就相当于3 * 4 * 5 * 6
sortWith函数:对集合中的元素执行排序
Array(11, 2, 5, 7, 19, 31).sortWith(_ <_)
闭包
闭包是指某变量不处于其有效作用域时,函数仍能够对变量进行访问,即为闭包。
def getExecuteFunc(key: String) =
(value:String) => println(key + ":" + value)
val executeDownload =getExecuteFunc("Download")
val executeCallback =getExecuteFunc("Callback")
// Download:http://github.com/5677
executeDownload("http://github.com/5677")
// Callback:10.224.17.1:5500
executeCallback("10.224.17.1:5500")
代码中两次调用getExecuteFunc函数,通过传入不同的key来创建不同的函数返回。例子中的key只是局部变量,但在getExecuteFunc执行完之后,仍继续存在于创建的函数之中并且反复调用。这个变量key超出作用域仍可使用的情况,即为闭包的含义。Scala中通过为每个函数创建对象来实现闭包,实际上对于getExecuteFunc创建的函数,key是作为函数对象的变量隐式存在的,因此每个函数会拥有不同的key变量。Scala通过编译器会确保闭包机制的实现。
SAM转换
JAVA中不支持直接将函数传入方法中作为入参,如果有类似需求,那么唯一的解决方案是定义一个实现了某接口的类的实例,该实例中仅包含单一方法;这些实现的接口都只包含单一抽象方法,也就是Single Abstract Method(SAM)。由于Scala与JAVA都是基于JVM实现,底层可以调用JAVA,因此调用Java方法时可能就不得不创建SAM传递给对应方法。但Scala本身是支持传递函数的,因此可以使用Scala提供的隐式SAM转换功能,将SAM转换为Scala函数。
Curring函数
Curring函数是指对函数变形,将接收两个入参的函数,转换为两个关联的函数;第一个函数接收第一个入参,返回接收第二个入参的第二个函数。因此在函数调用的过程中,其形式就变化为两个函数连续调用的形式。
def sum(begin: Int, end: Int)
= (begin toend).reduceLeft( _ + _)
sum(1, 10) // Int = 55
def sumRange(begin:Int):Int=>Int
=(end:Int) => (begin to end).reduce(_ + _)
sumRange(5)(10) // Int = 45
def sumSeprate(begin: Int)(end: Int)
= (begin to end).reduce(_ + _)
sumSeprate(10)(20) // Int = 165
return关键字
Scala语法中不使用return返回函数值,默认函数最后一行即为返回值。一般来说return通常用于匿名函数中返回给包含匿名函数的命名函数,并作为命名函数的返回值。使用return的匿名函数必须明确给出返回类型,否则将编译失败。参考以下示例:
def invoke(method: String) = {
def execute(method: String):String = {
// 使用return匿名函数须明确给出返回类型
return "Execute " + method
}
execute(method)
}
invoke("callback()")
// String =Execute callback()