函数和闭包
方法
//method: The most common way to define a function is as a member of some object;
//such a function is called a method.
def processFile(filename: File, width: Int): Unit = {
val source = scala.io.Source.fromFile(filename)
for (line <- source.getLines())
processLine(filename, line, width)
}
def processLine(filename: File, line: String, width: Int): Unit = {
if (line.length > width)
println(filename + ":" + line.trim)
}
局部函数:函数里面嵌套函数
def processFile(filename: File, width: Int): Unit = {
def processLine(filename: File, line: String, width: Int): Unit = {
if (line.length > width)
println(filename + ":" + line.trim)
}
val source = scala.io.Source.fromFile(filename)
for (line <- source.getLines())
processLine(filename, line, width)
}
局部函数可以访问包含它们的函数的参数,因此上面的函数可以改造为如下形式:
def processFile(filename: File, width: Int): Unit = {
def processLine(line: String): Unit = {
if (line.length > width)
println(filename + ":" + line.trim)
}
val source = scala.io.Source.fromFile(filename)
for (line <- source.getLines())
processLine(line)
}
一等函数
//简单入门
val fun = (x:Int) => x+1;
println(fun(3))
val fun02 = (x:Int)=>{
println("We")
println("are")
println("here!")
x+100
}
println(fun02(20))
//简单入门二
val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.foreach((x: Int) => println(x) )
val b = someNumbers.filter((x: Int) => x>0)
println(b) //List(5, 10)
//简单入门三,简写
val b = someNumbers.filter(x => x>0)
//使用占位符
val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.foreach(println _) //这里 _ 代表整个参数列表
val b = someNumbers.filter(_ >0)
//更一般的行为如下:
//多个下划线代表多个输入参数
scala> val f = (_: Int) + (_: Int)
f: (Int, Int) => Int = $$Lambda$1078/1672784022@3feeab43
scala> println(f(1,2))
3
scala> println(f(1,_:Int))
$line18.$read$$iw$$iw$$$Lambda$1081/2090086723@705e24fb
partially applied functions
scala> def sum(a: Int, b: Int, c: Int) = a + b + c
sum: (a: Int, b: Int, c: Int)Int
scala> sum(1,2,3)
res0: Int = 6
scala> val a = sum _
a: (Int, Int, Int) => Int = $$Lambda$1057/1239710170@2d24cdd9
scala> a(1,2,3)
res1: Int = 6
scala> a.apply(2,3,4)
res2: Int = 9
说明1:
object FunctionDemo {
def main(args: Array[String]): Unit = {
/**
* 部分应用函数:PAF ( PARTIALLY APPLIED FUNCTIONS)
*
* 这里发生了很多事情,名为a的变量指向了一个函数值对象,
* 这个函数值是一个从Scala编译器自动从 sum _ 这个 PAF表达式生成的类的实例
* 由编译器生成的这个类有一个接受三个参数的 apply方法,这是因为 生成的类继承自 Function3 这个特质
* 生成类的apply方法之所以接收三个参数,是因为表达式 sum _ 缺失的参数个数为 3
*
* Scala 编译器将表达式 a(1,2,3) 编译成 函数值的 apply方法调用,
* 因此 a(1,2,3) 是 a.apply(1,2,3) 的简写形式
*/
val a = sum _
println(a(1,2,3))
println(a.apply(1,2,3))
}
def sum(a: Int, b: Int, c: Int) = a + b + c
}
说明2:
scala> def sum(a: Int, b: Int, c: Int) = a + b + c
sum: (a: Int, b: Int, c: Int)Int
scala> val a = sum _
a: (Int, Int, Int) => Int = $$Lambda$1055/1568638055@5c234920
scala> val b = a(1,(_ : Int),3) //偏函数
b: Int => Int = $$Lambda$1058/497507806@5c5f0edc
scala> b(1)
res0: Int = 5
scala> b(3)
res1: Int = 7
//这里相当于调用了 b.apply(3)
闭包
简单的理解就是:函数内部的变量不在其作用域时,仍然可以从外部进行访问,听上去有些抽象;
package scala
object Closures {
def main(args: Array[String]): Unit = {
val addOne = makeAdd(1)
val addTwo = makeAdd(2)
println(addOne) //scala.Closures$$$Lambda$1/1789447862@1810399e
println(addTwo) //scala.Closures$$$Lambda$1/1789447862@32d992b2
println(addOne(1))
println(addTwo(1))
}
//闭包
def makeAdd(more: Int) = (x: Int) => x + more
def normalAdd(a: Int, b: Int) = a + b
}
运行结果如下:
scala.Closures$$$Lambda$1/1789447862@1810399e
scala.Closures$$$Lambda$1/1789447862@32d992b2
2
3
闭包对捕获到的变量的修改也能在闭包外被看到。如下:
scala> val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10)
scala> var sum = 0
sum: Int = 0
scala> someNumbers.foreach(sum += _)
scala> sum
res1: Int = -11
重复参数
//重复参数 args: String*,类似可变参数,可以遍历
scala> def echo(args: String*) =
| for (arg <- args) println(arg)
echo: (args: String*)Unit
scala> echo("hello", "world!")
hello
world!
scala> val arr = Array("What's", "up", "doc?")
arr: Array[String] = Array(What's, up, doc?)
//重复参数不能传入数组
scala> echo(arr)
:14: error: type mismatch;
found : Array[String]
required: String
echo(arr)
^
// 这种语法告诉编译器,将数组中的元素传入echo函数
scala> echo(arr: _*)
What's
up
doc?
带名字的参数
scala> def speed(distance: Float, time: Float): Float =
| distance / time
speed: (distance: Float, time: Float)Float
scala> speed(100,10)
res5: Float = 10.0
scala> speed(time = 10, distance=100)
res6: Float = 10.0
缺省参数
//缺省参数:函数中参数有默认值
scala> def printTime(out: java.io.PrintStream = System.out): Unit ={
| out.println("time:"+System.currentTimeMillis())
| }
printTime: (out: java.io.PrintStream)Unit
// 调用的时候可以不写有默认值的参数
scala> printTime()
time:1553658060529
scala> printTime(System.err)
time:1553658067245