spark快速开发之scala基础之5高阶函数,偏函数,闭包
高阶函数
高阶函数就是将函数作为参数或者返回值的函数。
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高阶函数,偏函数,闭包的更多相关文章
- spark快速开发之scala基础之1 数据类型与容器
写在前面 面向java开发者.实际上,具有java基础学习scala是很容易.java也可以开发spark,并不比scala开发的spark程序慢.但学习scala可有助于更快更好的理解spark.比 ...
- spark快速开发之scala基础之3类,对象,特征
类 scala的类定义非常灵活 class test4 class test2{} class test3(x:Int) 定义一个带构造函数的类 class Point (x : Int,y : In ...
- spark快速开发之scala基础之2控制流程
判断结构 大体与java相当.scala没有三元表达式. val num = if(1>0) 1 else 0 //相当于匿名函数 println(num) var num2 = 0 if(1& ...
- python 基础 4.3 高阶函数下和匿名函数
一 .匿名函数 顾名思议就是没有名字的函数,那为什么要设立匿名函数,他有什么作用呢?lambda 函数就是一种快速定义单行的最小函数,可以用在任何需要函数的地方. 常规版: def fun(x,y ...
- Scala学习十二——高阶函数
一.本章要点 在Scala中函数是”头等公民“(可以作为参数,返回值,赋值给其他); 可以创建匿名函数,通常还会交给其他函数; 函数参数可以给出需要稍后执行的行为; 许多集合方法都接受函数参数,将函数 ...
- scala学习笔记:高阶函数
scala> def power(y:Double)=(x:Double)=>Math.pow(x,y) warning: there were 1 deprecation warning ...
- python 基础 4.2 高阶函数上
一.高阶函数 把函数当做参数传递的一种函数 1>map()函数 map函数是python内置的一个高阶函数,它接受一个函数f和一个list,并把list元素以此传递给函数f,然后返回一个函数 ...
- Scala集合操作中的几种高阶函数
Scala是函数式编程,这点在集合操作中大量体现.高阶函数,也就是能够接收另外一个函数作为参数的函数. 假如现在有一个需要是将List集合中的每个元素变为原来的两倍,现在来对比Java方式实现和Sca ...
- Scala高阶函数与泛型
1. Scala中的函数 在Scala中,函数是“头等公民”,就和数字一样.可以在变量中存放函数,即:将函数作为变量的值(值函数). 2. scala中的匿名函数,即没有函数名称的函数,匿名函数常作为 ...
随机推荐
- 2018.4.27 java容器
一.容器的概念 在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,或者就叫做集合,集合就是将若干性质相同或相近的类对象组合在一起而形成的一个整体 二.容器与数组的关系 之所以需要 ...
- 开源WHMCS支付宝当面付和即时到账插件
开源WHMCS支付宝当面付和即时到账插件 链接: https://pan.baidu.com/s/1i5HU4hn 密码: crq7
- python __name__ 和__main__的使用领悟
__name__和__main__的使用 #hello.pydef sayHello(): str="hello" print(str); if __name__ == " ...
- ipc基础
ipc对象持久性 进程持久性:具有这种持久性的对象在持有它的最后一个进程关闭了该对象为止 内核持久性:这种IPC对象一直存在直到内核重新自举或显示删除该对象为止 文件系统持久性:具有这种持久性的对象只 ...
- rsync的daemon模式
官方文档:https://download.samba.org/pub/rsync/rsyncd.conf.html 1:daemon模式配置文件 rsync以daemon方式运行 ...
- shell(3)拼写检查与词典操作
1:Linux下,在/usr/share/dict下包含了词典文件,检查一个单词是否在词典里: #!/bin/bash #文件名:checkout.sh #检查给定的单词是否为词典中的单词 word= ...
- Java面试题 corejava(二)
65.JAVA 语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try 块中可以抛出异常吗?[基础] 答:Java 通过面向对象的方法进行 ...
- centos 7.x开放端口
1. 查看已打开的端口 # netstat -anp 2. 查看想开的端口是否已开 # firewall-cmd --query-port=666/tcp 若此提示 FirewallD is not ...
- CIFAR10数据可视化
一.数据准备 下载cifar-10-binary.tar.gz并解压,其中有多个bin文件,现对data_batch_1.bin进行可视化. 二.数据说明 该二进制文件存储的有10000张32X32的 ...
- redis 安装配置学习笔记
redis 安装配置学习笔记 //wget http://download.redis.io/releases/redis-2.8.17.tar.gz 下载最新版本 wget http://downl ...