文章地址:http://www.haha174.top/article/details/256207
1. 函数赋值给变量
scala 中函数可以独立定义,独立存在,而且可以直接将函数作为值赋值给变量
object hanshu {
def main(args: Array[String]): Unit = {
val helloFun=sayHello _
helloFun("haha")
}
def sayHello(name:String): Unit ={
println("hello:"+name)
}
}
2. 匿名函数
在scala 中函数也不需要命名,此时函数也被称为匿名函数。
在职直接定义某个函数之后,将函数赋值给某个变量;也可以将直接定义的匿名函数传入到其他的函数中
val helloFun1=(name:String) =>println(name)
3. 高阶函数
在scala 中可以直接将某个函数传入到其他的函数中,作为参数。这个功能是及其强大的,也是java 这种面向对象的语言所不必备的。
接收其他函数作为参数的返回值也被成为高阶函数
def greeting(func:(String)=>Unit,name:String){func(name)}
val helloFun1=(name:String) =>println("helloFun1:"+name)
greeting(helloFun1,"haha")
高阶函数的另外一个功能是将函数作为返回值
def getGreetingFunc(msg:String)=(name:String)=>println(msg+" "+name)
var geetingFunc=getGreetingFunc("hello");
getGreetingFunc("hello")("leo")
geetingFunc("leo");
4. 高阶函数类型推断
高阶函数可以自动推断出类型,而不需要写明类型;
而且对于只要一个参数的函数,还可以省去小括号;如果仅有的一个参数在右侧的函数体内只使用一次,则还可以将接收参数省略,并且用_来替代
def greeting(func:(String)=>Unit,name:String){func(name)}
greeting((name:String)=>println("hello"+name),"leo")
greeting((name)=>println("hello"+name),"leo")
greeting(name=>println("hello"+name),"leo")
greeting(_=>println("hello"+_),"leo")
5.scala 中常用的高阶函数
map 对传入的每个元素都进行映射返回处理后的元素
Array(1,2,3,4,5).map(2* _)
foreach 对传入的每个元素进行处理,没有返回值
(1 to 9).map("*"*_).foreach(println _)
filter 对传入的函数进行条件判断如果返回true 保留 返回false 过滤
(1 to 20).filter(_ % 2==0)
reduceLeft :从左侧元素开始,进行reduce 操作即先对元素1和元素2进行处理,然后将结果于元素3处理在于元素4处理,依次类推即为reduce
(1 to 9).reduceLeft(_ * _)
sortWith 对元素两个两个相比进行排序
Array(1,3,2,6,5).sortWith(_ < _)
5.闭包
函数在变量不处于其有效作用域时依旧能够对变量进行访问
def getGreetingFunc(msg:String)=(name:String)=>println(msg+" "+name)
var geetingFuncHello=getGreetingFunc("hello");
var geetingFuncHi=getGreetingFunc("hi");
两次调用getGreetingFunc 传入不同的msg 并创建不通的函数返回,
然而msg 只是一个局部变量,却在getGreetingFunc执行完成之后可以继续保存在函数中当调用 geetingFuncHi(” geetingFuncHi “)时,值问hi的msg 保留在函数的内部,可以继续使用,这种变量超过了作用域的情况称为闭包。
scala 通过每个函数创建对象来实现闭包,实际上对于getGreetingFunc 函数创建的函数 msg 作为函数变量的存在,因此每个函数才可以拥有不通的msg
6.SAM 转换
在java 中,不支持直接将一个函数传入一个方法当参数来使用,通常来说,唯一的方法就是定义一个是西安了某个接口的类的示例对象,该对象只有一个方法而这些接口都只有单个的抽象方法,也就是single abstract method 简称 SAM
由于scala 是可以调用java 代码的 因此当我们调用java 的某个方法的时候,可能九不得不创建SAM 传递给方法,非常麻烦但是scala 有时直接支持传递函数的,此时就可以使用scala 提供的在调用Java方法的时候,使用的功能SAM 转换,即将SAM转换位scala函数。
用使用SAM转换,需要使用scala 提供的特性,隐式转换 。
import javax.swing.JButton
import java.awt.event.ActionListener
import java.awt.event.ActionEvent
import javax.swing.JFrame
object Test {
/**
* 在Scala中,要某个函数做某件事时,会传一个函数参数给它。
* 而在Java中,并不支持传送参数。通常Java的实现方式是将动作放在一个实现某接口的类中,
* 然后将该类的一个实例传递给另一个方法。很多时候,这些接口只有单个抽象方法(single abstract method),
* 在Java中被称为SAM类型。
* @param args
*/
def main(args: Array[String]): Unit = {
var count = 0
val frame = new JFrame("SAM Testing")
val button = new JButton("Increment")
//java方式
// button.addActionListener(new ActionListener {
// override def actionPerformed(event: ActionEvent) {
// count += 1
// println(count)
// }
// })
/**
* scala方式: 隐式转换,将一种类型自动转换成另外一种类型,是个函数。
* 因为在Scala中,函数是头等公民,所以隐式转换的作用也大大放大了。
* 将这个函数和界面代码放在一起,就可以在所有预期ActionListener对象的地方,传入(ActionEvent)=>Unit函数参数。
* @param action
* @return
*/
implicit def makeAction(action: (ActionEvent) => Unit) =
new ActionListener {
override def actionPerformed(event: ActionEvent) { action(event) }
}
button.addActionListener((event: ActionEvent) => {count += 1; println(count)})
frame.setContentPane(button)
frame.pack()
frame.setVisible(true)
}
}
6.curring 函数
Curring函数指的是,将原来接受两个参数的一个函数,转换为两个函数,第一个函数接收原先的第一个参数然后返回接收原先第二个参数的函数
在函数调用的过程中就变成了连续调用的形式
def sum(a: Int, b: Int) = a + b
sum(1, 1)
def sum2(a: Int) = (b: Int) => a + b
sum2(1)(1)
def sum3(a: Int)(b: Int) = a + b
8.retion
// Scala中,不需要使用return来返回函数的值,函数最后一行语句的值,就是函数的返回值。在Scala中,return用于在匿名函数中返回值给包含匿名函数的带名函数,并作为带名函数的返回值。
// 使用return的匿名函数,是必须给出返回类型的,否则无法通过编译
def greeting(name: String) = {
def sayHello(name: String):String = {
return "Hello, " + name
}
sayHello(name)
}