一、Scala偏函数(PartialFunction)app
1.1 它之因此偏,是由于它并不处理全部可能的输入,而只处理那些能与至少一个case语句匹配的输入。在偏函数中,只能使用case语句,而整个函数必须用花括号包围。这与普通的函数字面量不一样,普通的字面量既能够用花括号,也能够用圆括号包围。函数
1.2 偏函数定义:def 函数名:PartialFunction[输入类型, 输出类型] = { case ... => ... }测试
1.3 偏函数能够链式,如 pf1 orElse pf2 orElse pf3 ...若是pf1不匹配则匹配pf2,再不匹配则匹配pf3,以此类推。若都不知足,则抛出scala.MatchError。this
1.4 使用isDefinedAt(x: A): Boolean方法来判断测试特定的输入是否与偏函数匹配,避免scala.MatchErrorscala
1.5 scala程序设计样例:设计
def cat(s1:String)(s2:String) = s1 + s2 /** * val hello = cat("Hello ") * hello("World") * 以上调用方式会抛出以下异常: * Error:(34, 18) missing argument list for method cat in object TestCase * Unapplied methods are only converted to functions when a function type is expected. * You can make this conversion explicit by writing `cat _` or `cat(_)(_)` instead of `cat`. */ //调用方式1: val hello = cat("Hello ") _ //注意下划线(_) hello("World") //Hello World //调用方式2: cat("Hello ")("World") //Hello World
1.6 Spark源码样例:code
/** * Process messages from [[RpcEndpointRef.send]] or [[RpcCallContext.reply)]]. If receiving a * unmatched message, [[SparkException]] will be thrown and sent to `onError`. */ def receive: PartialFunction[Any, Unit] = { case _ => throw new SparkException(self + " does not implement 'receive'") } /** * Process messages from [[RpcEndpointRef.ask]]. If receiving a unmatched message, * [[SparkException]] will be thrown and sent to `onError`. */ def receiveAndReply(context: RpcCallContext): PartialFunction[Any, Unit] = { case _ => context.sendFailure(new SparkException(self + " won't reply anything")) }
二、Curry化ci
2.1 Curry讲一个带有多个参数的函数转换为一系列函数,每一个函数都只有一个参数。源码
2.2 Scala程序设计样例:it
//def cat(s1:String)(s2:String) = s1 + s2 //上述函数改写为Curry def cat(s1:String) = (s2:String) => s1 + s2 val hello = cat("Hello ") //注意此处没有下划线(_) hello("World") //Hello World //调用方式2: cat("Hello ")("World") //Hello World
三、函数参数的调用方式:call-by-value与call-by-name
3.1 call-by-value:传给函数的参数是个值,若是是个表达式或者是另一个参数函数,则要先计算出表达式的值或者是要先获得参数函数执行后的返回值
/** * call-by-value * 不会输出begin...,直接抛出异常 * @param p 注意函数参数的定义无(=>) */ def callByValue(p:Boolean) = { println("begin...") p println("end...") } callByValue(1 / 0 == 0)
3.2 call-by-name:传给函数方法的参数是另一个参数函数,该参数函数在函数体内调用时执行
/** * call-by-name * 会先输出begin...,在抛出异常 * @param p 注意函数参数的定义有一个(=>) */ def callByName(p: => Boolean) = { println("begin...") p println("end...") } callByName(1 / 0 == 0 //等效于 def callByName(p:() => Boolean) = { println("begin...") p() //注意必须有圆括号 println("end...") } callByName(() => 1 / 0 == 0)