scala之函数和闭包

函数和闭包

方法

//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

你可能感兴趣的:(scala之函数和闭包)