scala学习笔记
@TOC
前言
一、匿名函数
没有名字的函数就是匿名函数,可以通过 函数表达式设置匿名函数
//不需要def关键字
//(n1: Int, n2: Int )是传参
//不需要返回值类型,使用类型推导
//=>{}表示函数体,不在使用returetype:={}
,
val f1 = (n1: Int, n2: Int ) => {
println("匿名函数被调用")
n1 + n2
}
println("f1类型=" + f1)
println(f1(10, 30))
}
//结果
//f1类型=digui$$$Lambda$5/1170794006@4cdbe50f
//匿名函数被调用
//40
二、高阶函数
1、函数作为参数
能够接受函数作为参数的函数,叫做高阶函数 (higher-order function)。
//sum 是接收一个Double,返回一个Double
def sum(d: Double): Double = {
d + d
}
//定义高阶函数,参数类型(函数类型,数据类型)
def higherFun(f: Double => Double, n1: Double) = {
f(n1)
}
//调用,第一个是sum函数,第二个是double数据类型
val res = higherFun(sum, 6.0)
//打印结果
println("res=" + res)
2、函数作为返回值
//func2没有指明返回值类型,所以返回f1 的时候用“f1 _”表示将f1整体返回
//如果,指定了返回值类型Char=>Boolean,直接写f1 即可
//def func1(a:Int):Char=>Boolean={
// def f1(b: String) = {
// if ((a == 0 && b == "")) true else false
// }
// f1
// }
//
def func2(a:Int)= {
def f1(b: String) = {
if ((a == 0 && b == "")) true else false
}
f1 _
}
println(func2(10)("10"))//false
//等价写法:var f1=func2(10)
// println(f1("10"))
println(func2(0)(""))//true
3、参数类型推断
说明:
- 参数类型是可以推断时,可以省略参数类型
- 当传入的函数,只有单个参数时,可以省去括号
- 如果变量只在=>右边只出现一次,可以用_来代替
//定义一个list
val list = List(1, 2, 3, 4)
//正常匿名函数
println(list.map((x:Int)=>x + 1)) //(2,3,4,5)
//如果X类型可以推断出来,类型可以省略(Int)
println(list.map((x)=>x + 1))
//如果只有1个参数,()可以省略
println(list.map(x=>x + 1))
//如果变量只在函数体内出现一次,可以用"_"代替
println(list.map(_ + 1))
二、闭包(closure)
闭包就是 一个函数和与其 相关的引用环境组合的一个 整体(实体)。
// y:int=>x-y是一个匿名函数
//这个匿名函数之外,又用到了x,那么这个匿名函数和x构成了一个闭包
//这里返回类型是一个匿名函数,所以也是高阶函数
def minusxy(x: Int) = (y: Int) => x - y
//f函数就是闭包.
val f = minusxy(20)
println("f(1)=" + f(1)) // 19
//当多次调用f时(可以理解多次调用闭包),
//发现使用的是同一个x, 所以x不变
println("f(2)=" + f(2)) // 18
println(minusxy(20)(3)) //17
在使用闭包时,主要搞清楚返回函数引用了函数外的哪些变量,因为他们会组合成一个整体(实体),形成一个闭包
//闭包练习
//定义一个闭包函数,先传入文件类型(如.jsp)
//调用的时候传入文件名称,如果是以该文件类型结束则返回文件名称
//如果不是,为该文件名加上后缀格式
def makeSuffix(suffix: String)={
(fileName:String)=>if (fileName.endsWith(suffix))
fileName else fileName+suffix
}
//先传入要检查的文件类型
val f2 = makeSuffix(".jsp")
//传入文件名
println(f2("text"))
println(f2("text2.jsp"))
//简写
println(makeSuffix(".jsp")("text3"))
println(makeSuffix(".xml")("text4"))
// *************************
结果
text.jsp
text2.jsp
text3.jsp
text4.xml
三、柯里化
- 函数编程中,接受 多个参数的函数都可以转化为接受 单个参数的函数,这个转化过程就叫柯里化
- 柯里化就是证明了函数只需要一个参数而已。其实我们刚才的学习过程中,已经涉及到了柯里化操作。
//定义一个闭包函数,先传入文件类型(如.jsp)
//调用的时候传入文件名称,如果是以该文件类型结束则返回文件名称
//如果不是,为该文件名加上后缀格式
//常规实现,一下传入两个参数
def makeSuffix1(suffix: String,fileName:)={
if (fileName.endsWith(suffix)) {
fileName
}
else {
fileName+suffix
}
}
println(makeSuffix1(".jps","text")
println(makeSuffix1(".jps","text2.jps")
//可以看到,这里每次都要输入文件类型,调用几次就要出入几次文件类型
************************************************
//闭包实现
def makeSuffix2(suffix: String)={
(fileName:String)=>if (fileName.endsWith(suffix))
fileName else fileName+suffix
}
//先传入要检查的文件类型,只需要传入一次文件类型
val f2 = makeSuffix2(".jsp")
//传入文件名
println(f2("text"))
println(f2("text2.jsp"))
// 闭包只需要传入一次文件类型,
*************************************
//柯里化实现,多个参数的函数都可以转化为接受 单个参数的函数
def makeSuffix3(suffix: String)(fileName:String)={
if (fileName.endsWith(suffix))
fileName else fileName+suffix
}
println(makeSuffix3(".jsp")("text3"))
println(makeSuffix3(".xml")("text4"))
柯里化就是以 函数式这种思想发展的必然产生的结果,就是y=f(x),只有一个变量
四、控制抽象
控制抽象是这样的函数,满足2个条件
- 参数是函数
- 函数参数没有输入值也没有返回值 好吧,这么说确实挺抽象
//控制抽象,这里定义了f1,没有参数,返回值为unit
def abstCort(f1 : =>Unit )={
println("抽象控制")
f1
}
//调用的时候,才需要把逻辑写进去
println(abstCort(println(20*10)))
综合性练习
自定义mywhile 的高阶函数,实现scala while的效果
//常规while的用法,while(循环条件){循环体}
var n=10
while(n>0){
println(n+" hello")
n-=1
}
//应用柯里化,自定义实现
var x = 10
def myWhile(conditon: => Boolean)(operate: => Unit): Unit = {
if (conditon) {
operate
myWhile(conditon)(operate)
}
}
//调用
myWhile(x > 0) {
x -= 1
println(x + " hello")
}