/**
* 这里讲一下闭包,因为这块不懂后面的东西讲解不了
*/
object Ex10_Closure {
/**
* 什么是闭包(Closure)简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。
* MDN 上面这么说:闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。
* 环境由闭包创建时在作用域中的任何局部变量组成。
* 这种官方的概念是比较难理解的,在面试的时候说出来也不是很专业,因为没办法有个具体的逻辑。
* 我个人认为,理解闭包的关键在于:外部函数调用之后其变量对象本应该被销毁,
* 但闭包的存在使我们仍然可以访问外部函数的变量对象,这就是闭包的重要概念。
*/
def outer(): Int ={
val a = 1
def inner():Int={
return a
}
return inner
}
/**
* 下面是两个闭包函数
* @param x
* @return
*/
def makeAdder1(x:Int):(Int=>Int) = y => x + y
def makeAdder2(x:Int)(y:Int) = x + y
/**
* 下面这一块是重点,因为这里面的问题就是问什么spark需要调用sc.clean(f)的原因
* spark调用这个函数就是想将不能序列化的且并不需要的一些变量或者对象去掉,保证程序执行
* class TestClass extends Serializable {
* var nonSer = new NonSerializable
* var x = 5
* def getX: Int = x
*
* def run(): Int = {
*
* withSpark(new SparkContext("local", "test")) { sc =>
* val nums = sc.parallelize(Array(1, 2, 3, 4))
* nums.map(_ + getX).reduce(_ + _)
* }
* }
* }
*
* 由于在spark中所对象是需要序列化进行传输的,上文调用了getX,所以需要序列化TestClass本身,但是nonSer是不能序列化的,
* 而nonSer在代码中根本没有用到,所以他回把这个对象去除进行序列化ClosureCleaner就是做这个的
*
*
*/
def main(args: Array[String]): Unit = {
println("func1:" + func1())
println("func2:" + func2())
println("func3:" + func3())
println("func4:" + func4())
}
/**
* 这里的返回值
* func1:64
* func2:-1
* func3:64
* func4:64
*
* 为什么第二个是-1,这个需要理解清楚
* 这么看基本看不出来什么所以只能反编译一下源码
* public int func1() {
* return this.func_map((Function1<Object, Object>)new Ex10_Closure$$anonfun$func1.Ex10_Closure$$anonfun$func1$1());
* }
*
* public int func2() {
* final Object o = new Object();
* int n;
* try {
* final Function1 func_Inner = (Function1)new Ex10_Closure$$anonfun.Ex10_Closure$$anonfun$2(o);
* n = this.func_map((Function1<Object, Object>)func_Inner);
* }
* catch (NonLocalReturnControl nonLocalReturnControl) {
* if (nonLocalReturnControl.key() != o) {
* throw nonLocalReturnControl;
* }
* n = nonLocalReturnControl.value$mcI$sp();
* }
* return n;
* }
*
* 反编译之后NonLocalReturnControl nonLocalReturnControl是这两个最大的区别,也是值不同的原因
* non-local return
*
* function a() {
* b() // non-local return if returns to after this call
* return
* }
*
* function b() {
* c(function () {
* return // <- the return in question
* })
* return
* }
*
* function c(f) {
* f() // local return if returns to after this call
* return
* }
* 如果b()里的匿名函数出现的return在执行后是返回到c()里,那就是local return。JavaScript的return就是这样的;
* 如果b()里的匿名函数出现的return在执行后是返回到a()里,那就是non-local return。Ruby的block里的return就是这样的。
*
* 现在解释一下为什么只有func2()会有non-local return
* 1、首先non-local return需要有return关键字并且包含匿名函数,没有return的不会触发non-local return,这个是scala实现机制,所以func3,func4没问题
* 2、func1为什么不触发non-local return,因为func1中的func_inner本身就是方法定义且直接调用者就是func_map,他将值返回给func_map,
* func_map将值返回给func1,所以不会触发non-local return
* 3、func2中的func_Inner定义的是一个有一个Int类型参数返回一个Int类型的方法变量,这里要注意一点他和func1的区别这也是他出现non-local return
* 的原因。func1是方法名叫func_inner,func2是变量名叫func_inner方法名是匿名的。
* scala中规定那就是return出现在非命名闭包里的时候,比如我们常见的lambda表达式里。一旦这些地方出现了return,
* 那么它就被赋予了退出其所在的外层函数的使命,如果一直到不了外层函数并且未被捕获,那么它可能会终止你的线程。
*
*
*/
def func1(): Int = {
def func_inner(i: Int): Int = {
if (i == 0) return -1
return i+1
}
func_map(func_inner)
}
def func2(): Int ={
try {
val func_Inner: (Int => Int) = i => {
if (i == 0) return -1
return i + 1
}
func_map(func_Inner)
} catch {
case e:Exception =>
e.printStackTrace()
return -100
}
}
def func3(): Int = {
def func_inner(i: Int): Int = {
if (i == 0) -1
else i+1
}
func_map(func_inner)
}
def func4(): Int ={
val func_Inner: Int => Int = i => {
if (i == 0) -1
else i+1
}
func_map(func_Inner)
}
def func_map(f: Int => Int): Int = {
0 to 10 map f sum
}
}
Githup项目LearningSpark代码讲解(四)
最新推荐文章于 2024-07-20 01:01:27 发布