Scala(3)

Functions and Closures

  • 这一章讲函数和闭包。毕竟Scala也算得上函数式语言了,函数在其中地位也是非常重要的

  • 定义在object里的函数叫做method,除了可以定义在object或者class里面,作为函数式语言,Scala也允许在函数中再定义,这样的的函数称为Local functionsLocal function只可在外层函数,不可以嵌套访问函数。只能通过外层函数间接访问内层函数。也就是只有外层函数才可以直接访问内层函数

  • 函数在Scala中是一等公民,也就是它和普通的Int等没什么区别,可以把函数作为参数传递,也可以返回函数。另外,像String等有自己的字面量,那么函数也有自己的字面量(也可以理解为匿名函数)。

  • function literalfunction value是两个不同,但是却又关联的概念。存在于源代码的叫做function literal,而编译之后就变成了function value。这种关系就类似于.scala文件和.class文件

  • Scala提供了占位符_来简化function literal。一般,一个占位符代表一个参数,而且这个参数不可以重用。多个占位符代表了多个参数

  • Partially applied function就是不给函数传递所有它需要的参数,而只是传递部分的参数。这么做的话,就可以产生新的function value。比如说,可以定义一个函数,用来返回两个数的和:

def addTwoNum(x:Int,y:Int)=x+y

我们可以只给addTwoNum函数传递一个值,比如说2,另外一个参数传递一个占位符,这样就可以产生一个新的function value,那么传递一个参数给这个新的function value,那么结果就是这个参数与2的和

val addOne=addTwoNum(1, _:Int)

addOne(4)

结果是5。不过在这里要注意,使用占位符时要指明参数类型。当然也可以写成柯里化的形式:

def addTwoNum(x:Int)(y:Int)=x+y

val addOne=addTwoNum(_:Int)(1)

addOne(4)

结果还为5。不过,占位符在前和在后不一样

val addOne=addTwoNum(1)(_)

addOne(4)

如果,占位符在后可以不用指明占位符的类型。不过,为了统一还是都写上类型吧

  • Closures的意思是函数引入了外部的参数,而这个参数并没有在函数定义时通过函数参数给出。如果,在定义函数时,给出了参数,那么这个参数在函数内部就叫做bound variable,而函数引用的外部参数就叫做free variable

  • free variable的变化是可以被Closures感知到的。比如:

var more=1

def addMore(x:Int)=x+more

addMore(2)

more=2

addMore(2)

两次调用addMore的结果分别是3和4。

  • Closures对free variable的改变,也会在Closures外部。比如:
var sum=0

val args=List(1,2,3,4,5)

args.foreach(sum += _)

sum

最后,sum的结果是15

  • Repeated parameter有点类似于python的可变参数。但是与Python可变参数不同的是,这里Repeated parameter已经确定好了参数类型,只可以传递可变长度,具有相同类型的参数。在Scala函数内部,则会把传递进来的可变参数组装成一个数组(数组只能装下相同类型的参数)。而Python的可变参数却可以传递不同类型的数组,在Python函数内部呢,则会把传递进来的可变参数组装成一个tuple(tuple可以装下不同类型的参数),这一点不同需要注意。当然也可以把一个数组传递给Repeated parameter,传递方法和把一个list传递给Pyhon的可变参数方法也是有点类似。不同Python是在list名前加一个 * ,而Scala则是在数组名加一个_再加上一个 *

  • Tail recursion是指一个函数的最后一个动作是调用一个函数(这个函数可以是自己,也可以是其他函数),但是不能够含有表达式,只能有一个function call。

  • Scala会对部分的尾递归函数进行优化,也就是那些直接调用自己的尾递归。如果尾递归调用了中间函数,那么就不能得到优化。优化了的尾递归在汇编程度上与正常的loop没有什么区别

Control Abstraction

  • 前面有一章介绍了Scala butil-in control structures,可以看到Scala内置的控制结构基本上不会太多,而这一章主要是介绍了使用Scala提供的函数式语言特性来构建自己的,较抽象的控制结构

  • 前面提到,Scala抛弃了breakcontinue关键字,是因为这个和函数字面值冲突,说明函数字面值更加重要。在这一章中,我们就看到了使用函数字面值的例子

  • 利用函数字面值,我们可以提取处公共的模块,然后把不同的参数或者运算方式作为函数字面值传递给函数。在函数内部,可以利用这个字面值进行计算,返回结果

  • Scala为了比较清楚的表示当前传递了一个函数字面值,做了一个比较取巧的方法。参数可以用()来扩起来,也可以用{}。之所以这样,是因为传递函数字面值时,我们就可以不适用括号,而是使用花括号了;而传递参数时,则使用括号。

  • 不过,要注意的是,只要传递一个参数时,才可以使用花括号。如果有多个参数时,则必须使用圆括号。其实,这不没什么。遇到函数接受多个函数时,我们可以应用柯里化把原来 one list parameter分成 multiple lists parameter,这样多个list只包含一个参数,就可以使用花括号了

  • 这一章还谈到了柯里化,这个概念还是挺容易懂得(不知道我理解的对不对。。。),柯里化的一个应用就是 partially applied function

  • 说到柯里化,要说说占位符的妙用:占位符真是个好东西。如果参数只使用了一次,那么就可以使用占位符来声明这个参数了,连参数类型都可以省略!这样的话,直接写上函数体就行了。不过,占位符只能用来参与表达式运算,不能使用来调用方法,如这样

_.methodName
  • ()在Scala中表示Unit类型

  • Scala还提供了机制,给我们自己定义的控制结构看起来像是 native language support。这个机制就是 call-by-Name,对应的就是 call-by-Value

  • call-by-Value就是传递会先对传递函数的参数进行 evaluate,然后在 evaluate后的参数传递进去。而如果是call-by-Name而不会这样,而是 a function value will be create whose apply method will evaluate for the expression。即,使用call-by-Name,会创建一个function value传递给函数,这个 function value的结果就是这个表达式的结果。当在函数内部需要这个表达式时,call this function value 然后就会得到结果。这个和 lazy evaluation是一个意思

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值