scala系列(四)函数与闭包 有更新!

  |   0 评论   |   1,092 浏览

37套精品Java架构师高并发高性能高可用分布式集群电商缓存性能调优设计项目实战视教程 置顶! 有更新!

(一)函数字面量(值函数)

函数字面量(function literal),也称值函数(function values),指的是函数可以赋值给变量。

一般函数具有如下形式: 

在高阶函数中,经常将只需要执行一次的函数定义为匿名函数作为参数传递给高阶函数,就好像map()filter()等高阶函数中经常能看到使用了匿名函数作为参数。匿名函数在这里有一个特性能够帮助我们写出更容易阅读的函数——参数推断

 

  def main(args: Array[String]): Unit = {

    // 函数字面量 function literal

    // =>左侧的表示输入,右侧表示转换操作

    val inc = (x:Int)=> x+1

    

    println(inc(9))

    

    //多个语句则使用{}

    val inc2 = (x:Int)=>{

        print(1);

        println(2);

        x+1

    }

    println(inc2(9))

    

    var arr = Array(10,20,30,50,80);

    println(arr.getClass)

    // 经典的map调用方法(写法1)

    println(arr.map(inc).mkString(","))

    // 匿名函数写法(写法2)

    println(arr.map((x:Int)=> x+1).mkString(","))

    // 花括方式(写法3)

    println(arr.map{(x:Int)=> x+1}.mkString(","))

    // 省略.的方式(写法4)

    println(arr map{(x:Int)=> x+1} mkString(","))

    // 参数类型推断写法(写法5)

    println(arr map{(x)=> x+1} mkString(","))

    // 函数只有一个参数的话,可以省略()(写法6)

    println(arr map{x=> x+1} mkString(","))

    // 如果参数右边只出现一次,则可以进一步简化(写法7)

    println(arr map{_+1} mkString(","))

    

    // 值函数简化方式(写法1)

    // val fun0 = _+1; 该定义方式不合法,因为无法进行类型推断

    // 正确方式

    val fun0 = (_:Int) + 2;

    // 值函数简化方式(写法2)

    val fun1:(Int) =>Int = _+20;

    

    println(fun0(0))

    println(fun1(1))

10

12

10

class [I

11,21,31,51,81

11,21,31,51,81

11,21,31,51,81

11,21,31,51,81

11,21,31,51,81

11,21,31,51,81

11,21,31,51,81

2

21

(二)高阶函数(函数参数)

带函数参数的函数由于是一个接受函数参数的函数,故被称为高阶函数,像之前讲到的map()函数就是高阶函数。如下例所示:

    // 高阶函数(1) 函数作为参数。上述map()就是高阶函数(函数参数)

    def apply(f:(Int)=>String,value:Int)={

      f(value);

    }

    def layout =(x:Int)=>"【"+x.toString()+"】";

    println(apply(layout,20))

【20】

上述代码中,apply函数接受一个函数f作为参数,接受一个Int类型的参数,进行f(v)运算,在下面又给出了f具体的定义(layout函数)。

同样的,高阶函数也可以产出另一个函数(即返回结果为一个函数,而不是某个值或对象),如下例所示:

    // 高阶函数(2) 函数作为返回值

    // val rect = (x:Int) => {(y:Int) => x * y}

    def rect(x:Int) = (y:Int) => x * y 

    val func = rect(6)

    println(func(5));

30

这里函数rectangle的输出是一个计算矩形周长的函数,矩形长已固定。

(三)函数闭包

闭包其实是一个很通用的概念,「闭包是词法作用域的体现」。很多大家耳熟能详的语言里都支持函数作为一类对象,比如JavaScript,Ruby,Python,C#,Scala,Java8.....,而这些语言里无一例外的都提供了闭包的特性,因为闭包可以大大的增强函数的处理能力,函数可以作为一类对象的这一优点才能更好的发挥出来。

那什么是闭包呢,一言以蔽之:一个持有外部环境变量的函数就是闭包。 

理解闭包通常有着以下几个关键点:
1.函数
2.自由变量
3.环境

举个栗子:

    var more = 5;

    val fun1 = (x:Int) => x + more;

    

    println(fun1(10));

    var list = List(1,2,3,4,5);

    var sum = 0;

    list.foreach(x=>sum=sum+x)

    println(sum)



在这个例子里函数fun1因为捕获了外部作用域(环境)中的变量more,因此形成了闭包。 而由于变量more并不属于函数fun1,所以在概念里被称之为「自由变量」。

 


评论

发表评论

validate