函数与闭包

scala中函数4种的表现形式{

  对象中的函数,

  内嵌在函数的函数,

  函数字面量,

  函数值

1)对象中的函数

  不解释。

2)内嵌在函数中函数

  控制helper函数的方式 一般限制访问级别private。scala可以通过内嵌方式控制(前者同样生效),类似方法中的变量(本地变量)。

  本地函数可以访问外层的函数参数等。scala的嵌套和作用域思想是什么???为何嵌套和作用域的思想对于函数是一等公民的语言中及其重要???

3)一等函数:函数字面量与函数值

  什么是函数字面量?基本类型绝大部分都可以通过字面量来表示,比如 4,12 表示一个int值 2.3 表示double值等,函数也可以通过这种字面量来表示一个值(函数值)。而def形式是在定义一个函数,并不是一个值。再例如 val a:Int = 3定义Int类型的a,5是Int类型的值。

  一等函数,不仅可以通过定义和调用使用它们,还可以写成函数字面量,当作值来传递。

  函数字面量被编译进类,并在运行时形成对象(及函数值)。

  函数字面量和函数值的区别:源码与运行时。如同蓝图与建筑,类与对象。(这里函数字面量就是类,函数值就是对象)

  函数值既是对象又是函数

val increase = (x: Int) => x + 1  //像对象一样传值给变量
increase(10)    //像函数一样调用参数

  函数字面量中的方法部分可以用{}

val increase = (x: Int) => {
    val y = x + 1
    y +1
}

  既然函数作为值,就可以传递给函数,形成高阶函数。

  栗子:集合类中的两个方法foreach与filter同是以函数作为参数的函数。

目标类型化 缩减函数字面量的无用字符??

占位符 _ 一个占位符只能表示一个函数参数,且这个函数参数在函数体中只能被用到一次。

  栗子:(x:Int) => x+1    写成  _ + 1

     (x:Int,y:Int) => x+y   写成  (_:Int) + (_:Int) 不简洁,但是如果是某一函数调用两个参数的函数时,可以通过类型推断(?)直接写成xx.yy(_ + _)

部分应用函数

1.通过部分应用函数将def转换为函数值

def sum(a:Int,b:Int,c:Int) = a+b+c
val temp_sum = sum _

2.当指定了一些函数参数时候 部分应用函数的占位符还需要添加类型

scala> val mysum = sum(1,_,_)
<console>:11: error: missing parameter type for expanded function ((x$1, x$2) => sum(1, x$1, x$2))
       val mysum = sum(1,_,_)
                         ^
<console>:11: error: missing parameter type for expanded function ((x$1: <error>, x$2) => sum(1, x$1, x$2))
       val mysum = sum(1,_,_)
                           ^

scala> val mysum = sum(1,_:Int,_:Int)
mysum: (Int, Int) => Int = <function2>

3. 1和2的原理是编译器将函数编译成类,mysum(2,3)其实在调用mysum.apply(2,3)。 apply方法?

闭包

自由变量与绑定变量

闭包是函数值。通过自由变量创建的函数值称为闭包。

闭包捕获自由变量而不是变量所指向的值。所以变量的改变会影响闭包,同样闭包的也能改变自由变量。

scala> var s = 10
s: Int = 10

scala> val mydef = (a:Int) => a + s
mydef: Int => Int = <function1>

scala> mydef(1)
res0: Int = 11

scala> s = 12
s: Int = 12

scala> mydef(1)
res1: Int = 13
scala> val sumList = List(1,2,-1,-2,4)
sumList: List[Int] = List(1, 2, -1, -2, 4)

scala> var sum  = 0
sum: Int = 0

scala> sumList.foreach(sum += _)

scala> sum
res3: Int = 4

个人理解 当闭包的自由变量是函数参数时。每一次函数传参都会形成新的闭包。由于函数参数是val 所以函数体内形成的闭包的自由变量恒定。

重复参数

定义重复参数只要在类型后面加*

scala> def sum(a:Int*) = a.sum
sum: (a: Int*)Int

scala> sum(1)
res4: Int = 1

scala> sum(1,3,4)
res5: Int = 8

形成的类型其实是数组。所以可以调用数组sum方法。

然而不能传数组给sum函数,需要将数组转为arr: _*形式(这种形式是告诉编译器把数组中的每一个参数传给函数)

scala> val arr = Array(1,2,3,4,5,6,7,8,9)
arr: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> sum(arr)
<console>:13: error: type mismatch;
 found   : Array[Int]
 required: Int
       sum(arr)
           ^

scala> sum(arr: _*)
res7: Int = 45

指定名字的调用参数

scala> def speed(distance: Float, time: Float): Float = distance / time
speed: (distance: Float, time: Float)Float
scala> speed(100, 10)
res9: Float = 10.0

scala> speed(distance=100,time=10)
res10: Float = 10.0

scala> speed(time=10,distance=100)
res11: Float = 10.0

一般常用方式是默认顺序+指定参数 配合使用 (没记错的话,Spark中比较常见)

默认的参数值

scala> def printTime(out:java.io.PrintStream = Console.out) = out.println("time = " + System.currentTimeMillis())
printTime: (out: java.io.PrintStream)Unit

scala> printTime()
time = 1478591319201

scala> printTime(Console.err)
time = 1478591327893

然而默认的参数值常常与指定参数配合使用

scala> def printTime2(out: java.io.PrintStream = Console.out, divisor: Int = 1) = out.println("time = " + System.currentTimeMillis()/divisor)
printTime2: (out: java.io.PrintStream, divisor: Int)Unit

scala> printTime2(out = Console.err)
time = 1478591428641

scala> printTime2(divisor = 1000)
time = 1478591435

尾递归:scala编译器对尾递归进行了特殊处理,使得与指令形式的while效率相当。但由于JVM的限制使得尾递归并不能完全支持(间接尾递归,函数值的尾递归),支持直接尾递归。

时间: 2024-10-22 14:01:23

函数与闭包的相关文章

14.匿名函数和闭包

匿名函数和闭包 学习要点:1.匿名函数2.闭包 匿名函数就是没有名字的函数,闭包是可以访问一个函数作用域里变量的函数.声明:本节内容需要有面向对象和少量设计模式基础. 一.匿名函数 //普通函数function box(){ //函数名是box return 'Lee'; } //匿名函数function(){ //匿名函数,会报错,单独的匿名函数是无法运行的 return 'Lee';} //通过表达式自我执行(function box(){ //封装成表达式 alert('Lee');})(

匿名函数和闭包

匿名函数和闭包匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数.一. 匿名函数//普通函数functionbox() { //函数名是 boxreturn'Lee';}//匿名函数function() { //匿名函数,会报错return'Lee';}//通过表达式自我执行(function box() { //封装成表达式alert('Lee');})(); //()表示执行函数,并且传参//把匿名函数赋值给变量var box = function() { //将匿名函数赋给

5.初识python装饰器 高阶函数+闭包+函数嵌套=装饰器

一.什么是装饰器? 实际上装饰器就是个函数,这个函数可以为其他函数提供附加的功能. 装饰器在给其他函数添加功能时,不会修改原函数的源代码,不会修改原函数的调用方式. 高阶函数+函数嵌套+闭包 = 装饰器 1.1什么是高阶函数? 1.1.1函数接收的参数,包涵一个函数名. 1.1.2 函数的返回值是一个函数名. 其实这两个条件都很好满足,下面就是一个高阶函数的例子. def test1(): print "hamasaki ayumi" def test2(func): return t

Swift函数和闭包

函数 Swift 使用func关键字声明函数: 1 func greet (name: String, day: String) -> String { 2 return "Hello \(name), today is \(day)." 3 } 4 greet ("Bob", "Tuesday") 通过元组(Tuple)返回多个值: 1 func getGasPrices () -> (Double, Double, Double)

[连载]JavaScript讲义(04)--- 函数和闭包

点击下载该例子的源代码 [连载]JavaScript讲义(04)--- 函数和闭包,布布扣,bubuko.com

javascript匿名函数与闭包

匿名函数是相对于有名字的函数 如function setAge(){}函数名为setAge 而类似于function(){}则就是一个匿名函数 有名字的函数执行时可以写成setAge(),而没有名字的函数则执行要写成(function())(); 另一种方式是把匿名函数赋值给一个变量来使用 var a=function(){ alert("hello,world"); } a(); 匿名函数传参 (function(age){ return age; })(100); 匿名函数产生闭包

前端学习 第六弹: javascript中的函数与闭包

前端学习 第六弹:  javascript中的函数与闭包 当function里嵌套function时,内部的function可以访问外部function里的变量 function foo(x) {    var tmp = 3;    function bar(y) {        alert(x + y + (++tmp));    }    bar(10);}foo(2) 这时无论怎么运行输出的都是16,但这不是闭包 如果我们返回内部函数,内部function会close-over外部fu

JavaScript 函数之 ------------------ 闭包

谈到闭包,人们常常会把匿名函数和闭包混淆在一起.闭包是指由权访问另一个函数作用域中的变量的函数.创建闭包的常见方式,就是在一个函数内部创建另一个函数,仍以前面的 createComparisonFunction()函数为例 1 function createComparisonFunction(propertyName){ 2 return function(object1,object2){ 3 var value1 = object1[propertyName]; 4 var value2

匿名函数和闭包规避xdebug限制的函数递归深度限制

PHP版本5.6 先来个简单的用递归求和,代码如下: function add($n){     if($n === 1)return 1;     return add($n - 1); } echo add(256);  运行时报错: Maximum function nesting level of '256' reached, aborting! 这个报错的意思就是函数的递归深度最大是256,不能大于或等于256.在网上查找资料发现,这个是xdebug做的限制,可以通过更改配置文件来修改

JavaScript中的匿名函数及函数的闭包以及作用域

1. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85