高阶函数

高阶函数就是将函数作为参数或者返回值的函数。

object function {

  def main(args: Array[String]): Unit = {
println(test(f,10))
} def test(f:Int => String , num : Int) = f(num) def f(num:Int) : String = {
10 + num + ""
} }

在spark中,经常将只需要执行一次的函数定义为匿名函数作为参数传递给高阶函数。如map,flatMap。

以map为例,最全面的写法是

object function {
def main(args: Array[String]): Unit = {
val list = List("spark","hadoop","hbase")
list.map(f2:String=>(String,Int)).foreach(println)
}
def f(x:String) : (String,Int) = {
(x,1)
}
}

匿名函数的写法

list.map((x:String) => (x,1)).foreach(println)

利用匿名函数的参数推断,可以进一步简化的写法

list.map((x) => (x,1)).foreach(println)

如果只有一个参数

list.map(x => (x,1)).foreach(println)

可以使用_代替参数

list.map((_,3)).foreach(println)

偏应用函数

偏应用函数指的是如果一个函数有n个参数,为其提供少于n个参数的函数叫做偏应用函数。又叫做部份函数。其实也点类似于方法重载。

  def f1(x:Int,y:Int,z:Int) = x+y+z

  def f2(y:Int,z:Int) = f1(1,y,z)

偏函数

scala里的偏函数也是数学中的一个概念,指定义域X中可能存在某些值在值域Y中没有对应的值,通俗点说就是入参是在指定的范围内,因此它比普通的函数多了个isDefinedAt方法,用于判断参数是否在该函数的接受范围内。不同于普通函数,偏函数是scala.PartialFunction[-A,+B]的对象。

先看一个例子

//这是一个偏函数
val pf: PartialFunction[Int, String] = {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
} //这不是一个偏函数
val pf2: PartialFunction[Int, String] = {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
case _ => "else"
} println(pf(1)) //One
println(pf2(4)) //else
println(pf(4)) //异常

偏函数的定义

PartialFunction[Int, String] 
Int为输入类型,String为返回值类型。

pf的定义域为所有int,值域为【1,2,3】,除了【1,2,3】以外的参数并没有与之对应的返回值。所以pf是一个偏函数。调用偏函数传入定义域以外的参数就会报错,但是偏函数提供了其它的方法来避免这种情况。

使用isDefinedAt来判断是否可以传入此参数,返回一个布尔值。

println(pf.isDefinedAt(4)) //false

orElse相当于连接。条件是两个偏函数的类型是一样的。

val pf: PartialFunction[Int, String] = {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
} val pf2: PartialFunction[Int, String] = {
case 4 => "Four"
case 5 => "Five"
case 6 => "Six"
} pf orElse pf2相当于 val pf: PartialFunction[Int, String] = {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
case 4 => "Four"
case 5 => "Five"
case 6 => "Six"
}

andThen

对函数的结果进行下一步的处理。前提是前一个的偏函数返回值类型是后一个偏函数的输入类型。如,上面两个函数就是报错。
    pf andThen pf3
pf3 andThen pf//异常 val pf2: PartialFunction[Int, String] = {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
case _ => "else"
} val pf3: PartialFunction[String, String] = {
case "One" => "One"
case "Two" => "Two"
case "Three" => "Three"
case "else" => "else"
}

偏函数的意义在于粒度的问题。可以把一个函数细分,然后在不同的功能的时候对这些函数进行排列组合,自由灵活的达到想要的功能。

柯里化

看代码最直观

  def add(x:Int,y:Int,z:Int) = x+y+z
def add2(x:Int)(y:Int)(z:Int) = x+y+z

函数add到add2的过程就是柯里化。两个函数参数类型个数和返回值都是一样的。但是过程不一样。

函数add直接相加。

函数add2先演变为

val result = add2(x)

再演变为

val  add2(y:Int) = result + y
val result2 = add2(y)

最后是

val add2(z:Int) = result2 + z
val result3 = add2(z)

关于其应用及其意义,参照fold,aggregate。

闭包

闭包函数返回值依赖于函数外部的变量。

  val y : Int = 0
def f(x:Int) = x + y
println(f(10))

我们定义了一个形参x,调用的时候传入,另一个函数外部的变量y,是一个自由变量。这样就定义了一个闭包。因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。

spark快速开发之scala基础之5高阶函数,偏函数,闭包的更多相关文章

  1. spark快速开发之scala基础之1 数据类型与容器

    写在前面 面向java开发者.实际上,具有java基础学习scala是很容易.java也可以开发spark,并不比scala开发的spark程序慢.但学习scala可有助于更快更好的理解spark.比 ...

  2. spark快速开发之scala基础之3类,对象,特征

    类 scala的类定义非常灵活 class test4 class test2{} class test3(x:Int) 定义一个带构造函数的类 class Point (x : Int,y : In ...

  3. spark快速开发之scala基础之2控制流程

    判断结构 大体与java相当.scala没有三元表达式. val num = if(1>0) 1 else 0 //相当于匿名函数 println(num) var num2 = 0 if(1& ...

  4. python 基础 4.3 高阶函数下和匿名函数

    一 .匿名函数 顾名思议就是没有名字的函数,那为什么要设立匿名函数,他有什么作用呢?lambda 函数就是一种快速定义单行的最小函数,可以用在任何需要函数的地方.   常规版: def fun(x,y ...

  5. Scala学习十二——高阶函数

    一.本章要点 在Scala中函数是”头等公民“(可以作为参数,返回值,赋值给其他); 可以创建匿名函数,通常还会交给其他函数; 函数参数可以给出需要稍后执行的行为; 许多集合方法都接受函数参数,将函数 ...

  6. scala学习笔记:高阶函数

    scala> def power(y:Double)=(x:Double)=>Math.pow(x,y) warning: there were 1 deprecation warning ...

  7. python 基础 4.2 高阶函数上

    一.高阶函数 把函数当做参数传递的一种函数   1>map()函数 map函数是python内置的一个高阶函数,它接受一个函数f和一个list,并把list元素以此传递给函数f,然后返回一个函数 ...

  8. Scala集合操作中的几种高阶函数

    Scala是函数式编程,这点在集合操作中大量体现.高阶函数,也就是能够接收另外一个函数作为参数的函数. 假如现在有一个需要是将List集合中的每个元素变为原来的两倍,现在来对比Java方式实现和Sca ...

  9. Scala高阶函数与泛型

    1. Scala中的函数 在Scala中,函数是“头等公民”,就和数字一样.可以在变量中存放函数,即:将函数作为变量的值(值函数). 2. scala中的匿名函数,即没有函数名称的函数,匿名函数常作为 ...

随机推荐

  1. [CSL 的字符串][栈,模拟]

    链接:https://ac.nowcoder.com/acm/contest/551/D来源:牛客网题目描述 CSL 以前不会字符串算法,经过一年的训练,他还是不会……于是他打算向你求助. 给定一个字 ...

  2. error: invalid use of void expression

    void*类型定义的指针变量只可以接收对象的地址,而没有对象类型这个概念.所以void*指针变量是不能直接用“*指针变量”去访问,需要强制类型转换后才能“间接”访问: *(type*)指针变量,必须给 ...

  3. php 多线程

    windows下安装php真正的多线程扩展pthreads教程 http://www.thinkphp.cn/topic/22676.html PHP 安装 Pthreads (解决 class Th ...

  4. 用Redis存储Tomcat集群的Session实现session共享

    一.存储 前段时间,我花了不少时间来寻求一种方法,把新开发的代码推送到到生产系统中部署,生产系统要能够零宕机.对使用用户零影响. 我的设想是使用集群来搞定,通过通知负载均衡Nginx,取下集群中的To ...

  5. Hanlp1.7版本的新增功能一览

    Hanlp1.7版本在去年下半年的时候就随大快的DKH1.6版本同时发布了,截至目前1.7大版本也更新到了1.7.1了.本篇分别就1.7.0和1.7.1中新增的功能做一个简单的汇总介绍. HanLP ...

  6. [转]Python如何引入自定义模块?

    转自 http://www.cnblogs.com/JoshuaMK/p/5205398.html Python运行环境在查找库文件时是对 sys.path 列表进行遍历,如果我们想在运行环境中注册新 ...

  7. Spring Boot - 配置介绍

    Spring Boot 针对常用的开发场景提供了一系列自动化配置来减少原本复杂而又几乎很少改动的模板配置内容,但是,我们还是需要了解如何在Spring Boot中修改这些自动化的配置,以应对一些特殊场 ...

  8. EF LIKE 查询

    <!-- CSDL content --> <edmx:ConceptualModels> <Schema Namespace="Model" Ali ...

  9. c# 动态绘制直线和曲线

    c# 动态绘制直线和曲线   在本案例中利用Graphics对象动态地绘制直线和曲线.程序运行后,选择“直线”单选按钮,然后按下鼠标左键拖动鼠标就可以绘制直线,选择“曲线”单选按钮,然后移动鼠标就可以 ...

  10. PHP 获取数组是几维数组

    // 判断数组是几维数组$data = array(); // 是你要判断的数组$al = array(0);function aL($data,&$al,$level=0){ if(is_a ...