美文网首页
【2019-05-21】函数和闭包

【2019-05-21】函数和闭包

作者: BigBigFlower | 来源:发表于2019-05-21 14:01 被阅读0次

    (1)方法
    定义函数最通用的方法是作为某个对象的成员。这种函数称为方法。

    //带私有的processLine方法的LongLines 对象
    import scala.io.Source
    
    object LongLines {
    //processFile方法以filename和width为参数,文件名用来创建Source对象,并通过for表达式的发生器调用source的getLines方法。
      def processFile(filename: String, width: Int) {
        val source = Source.fromFile(filename)
        for (line <- source.getLines) //getLines返回的枚举器能在每次枚举中从文件里取出一行
          processLine(filename, width, line)
      }
    
      private def processLine(filename: String,
          width: Int, line: String) {
    
        if (line.length > width)
          println(filename +": "+ line.trim)
      }
    }
    
    object FindLongLines {
      def main(args: Array[String]) {
        val width = args(0).toInt
        for (arg <- args.drop(1))
          LongLines.processFile(arg, width)
      } 
    } 
    

    (2)本地函数
    把函数定义在别的函数内部,类似于本地变量。

    import scala.io.Source
    
    object LongLines2 {
      object LongLines {
        def processFile(filename: String, width: Int) {
        
          def processLine(filename: String,
              width: Int, line: String) {
        
            if (line.length > width)
              print(filename +": "+ line)
          }    
        
          val source = Source.fromFile(filename)
          for (line <- source.getLines) {
            processLine(filename, width, line)
          }
        }
      }
    
      object FindLongLines {
        def main(args: Array[String]) {
          val width = args(0).toInt
          for (arg <- args.drop(1))
            LongLines.processFile(arg, width)
        } 
      } 
    
      def main(args: Array[String]) = FindLongLines.main(args)
    }
    

    直接使用外部processLine函数的参数

    import scala.io.Source
    
    object LongLines3 {
      import scala.io.Source
      
      object LongLines {
      
        def processFile(filename: String, width: Int) {
      
          def processLine(line: String) {
            if (line.length > width)
              print(filename +": "+ line)
          }    
      
          val source = Source.fromFile(filename)
          for (line <- source.getLines)
            processLine(line)
        }
      }
    
      object FindLongLines {
        def main(args: Array[String]) {
          val width = args(0).toInt
          for (arg <- args.drop(1))
            LongLines.processFile(arg, width)
        } 
      } 
    
      def main(args: Array[String]) = FindLongLines.main(args)
    }
    
    

    (3)头等函数
    Scala的函数是头等函数(first-class function)
    可以把它们写为匿名字面量,并作为值传递
    ex.对数执行递增操作的函数字面量:

    //指明这个函数把左边的东西(任何整数x)转变成右边的东西(x+1)
    (x: Int) => x + 1
    //res14: Int => Int = $$Lambda$1151/993016696@685e97e0
    //定义为变量形式
    var increase = (x: Int) => x + 1
    increase(15)
    //res15: Int = 16
    

    (4)函数字面量的短格式
    函数字面量更简短的方式是去除参数

    //过滤
    val someNumbers = List(-11, -10, -5, 0, 5, 10)
    someNumbers.filter((x) => x > 0)
    //List[Int] = List(5, 10)
    

    (5)占位符语法
    如果想让函数字面量更简洁,可以把下划线当作一个或更多参数的占位符,只要每个参数在函数字面量内仅出现一次。

    someNumbers.filter(_ > 0)
    //res18: List[Int] = List(5, 10)
    val f = (_: Int) + (_: Int)
    f(5, 10)
    //res19: Int = 15
    

    (6)部分应用函数
    单个下划线还可以替换整个参数列表

    someNumbers.foreach(println _)
    //-11
    //-10
    //-5
    //0
    //5
    //10
    

    部分应用函数是一种表达式,不需要提供函数需要的所有参数,仅提供部分,或不提供所需参数。

    def sum(a: Int, b: Int, c: Int) = a + b + c
    sum(1, 2, 3)
    //res22: Int = 6
    val a = sum _
     a(1, 2, 3)
    //res23: Int = 6
    

    (7)闭包
    依照函数字面量在运行时创建的函数值(对象)被称为闭包。名称源于通过“捕获”自由变量的绑定,从而对函数字面量执行的“关闭”行动。不带自由变量的函数字面量被称为封闭项。

    var more = 1
    val addMore = (x: Int) => x + more
    addMore(10)
    // res19: Int = 11
    

    (8)重复参数
    scala可以指明函数的最后一个参数是重复的,从而允许客户向函数传入可变长度参数列表,想要标注一个重复参数,可以在参数的类型之后放一个参数。

    def echo(args: String*) =   for (arg <- args) println(arg)
    echo("one")
    //one
    echo("hello", "world!")
    //hello
    //world!
    

    (9)尾递归
    如果想把更新var的while循环转换成仅使用val这种更函数式的风格,可以使用递归。

    object Approximate {
      def isGoodEnough(guess: Double): Boolean = {
          println("guess [" + guess + "]")
          Math.abs(guess*guess - 2.0)  <  1.0E-6
      }
    
      def improve(guess: Double): Double =
          (guess + 2.0/guess)/2.0
          
      def approximate(guess: Double): Double = 
        if (isGoodEnough(guess)) guess
        else approximate(improve(guess))
    
      def approximateLoop(initialGuess: Double): Double = {
        var guess = initialGuess
        while (!isGoodEnough(guess))
          guess = improve(guess)
        guess
      }
    
      def main(args: Array[String]) {
        approximateLoop(3.3)
      }
    }
    

    尾递归函数跟踪

    object TailRecursion {
      def boom(x: Int): Int = 
        if (x == 0) throw new Exception("boom!")
        else boom(x - 1) + 1
    
      def bang(x: Int): Int = 
       if (x == 0) throw new Exception("bang!")
       else bang(x - 1)
    
      def main(args: Array[String]) {
        try {
          boom(3)
        } catch {
          case ex: Exception => ex.printStackTrace()
        }
    
        try {
          bang(5)
        } catch {
          case ex: Exception=> ex.printStackTrace()
        }
      }
    }
    

    相关文章

      网友评论

          本文标题:【2019-05-21】函数和闭包

          本文链接:https://www.haomeiwen.com/subject/lqqkzqtx.html