Scala闭包


1.Scala_基础

package com.ecust.demo

/**
 * @author Jinxin Li
 * @create 2021-01-11 15:25
 */
object SparkCore05_Closure_Scala {
  //将函数作为返回值来使用
  def main(args: Array[String]): Unit = {

    def test() ={
      def inner()={
      }
      println("xxxxxx")
      //下划线表示将函数作为对象来使用
      val f = inner _
      f
    }

    //对上述方法调用
    val f: () => Unit = test()
    f()

    test()()

    def test1() ={
      def inner()={
      }

      //下划线表示将函数作为对象来使用
      inner _
    }

    //todo > 也可以直接指定类型 但是在企业中不这么用
    def test2():()=>Unit ={
      def inner()={
      }
      //下划线表示将函数作为对象来使用
      inner
    }

  }
  /*public User getUser(){
    User user = new User();

    return user;
  }*/
}

2.闭包

package com.ecust.demo

/**
 * @author Jinxin Li
 * @create 2021-01-11 15:34
 */
object SparkCore06_Closure_Scala {
  def main(args: Array[String]): Unit = {

    //1.outer函数=>方法
    //2.参数x编译后应该是方法的局部变量 局部变量有效范围是当前方法内部有效
    //3.inner函数=>文件中方法
    //4.inner方法执行时间点:在outer方法执行之后9
    //5.outer方法如果执行完了会弹出栈,其中的局部变量会回收
    //6.inner方法凭什么能用x 底层进行特殊操作,一个函数如果使用了外部的变量,需要将变量的生命周期改变
    //7.函数将变量包含到函数的内部,形成一个闭合的效果,称之为闭包
    //8.早期是使用匿名内部类实现的
    def outer(x:Int)={
      println("执行外部程序")
      def inner(y:Int)={
        println("执行内部程序")
        x+y
      }
      inner _
    }

    val f: Int => Int = outer(20)
    println(f)

    val i: Int = f(20)
    println(i)

//    println(outer(20)(20))
  }
}

3.Java模仿

package com.ecust.demo;

/**
 * @author Jinxin Li
 * @create 2021-01-11 15:49
 */
public class SparkCore08_Closure_Scala {
    private static int x = 10;

    public static void main(String[] args) {

        SparkCore08_Closure_Scala obj = new SparkCore08_Closure_Scala();

        //先执行方法outer,方法弹出栈
        int outer = obj.outer(20);


        //在执行方法inner
        int inner = obj.inner(20);

//        System.out.println(x);

        System.out.println(inner);
    }

    //java方法中不能写方法
    /*public void outer(int x){
        public void inner(){

        }
    }*/

    public int outer(int x){
        return x;
    }

    public int inner(int y){
        return x+y;
    }
}

4.实战1

package com.ecust.demo


import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
 * @author Jinxin Li
 * @create 2021-01-11 16:19
 */
object SparkCore09_Closure_Spark {
    def main(args: Array[String]): Unit = {
      val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
      val sc: SparkContext = new SparkContext(conf)

      val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))

      val user = new user()

      rdd.foreach(
        num=>{
          println("age:" + user.age+num)
        }
      )

      sc.stop()
    }
  //这里可以选择是否进行序列化类
  class user extends Serializable {
    var age:Int= 30
  }
}

5.实战2

package com.ecust.demo

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
 * @author Jinxin Li
 * @create 2021-01-11 16:19
 * 这种情况下还是不能运行,因为需要进行闭包检查,当executor内部引用了外部变量时,就会监测外部变量能否使用
 */
object SparkCore10_Closure_Spark {
    def main(args: Array[String]): Unit = {
      val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
      val sc: SparkContext = new SparkContext(conf)

      val rdd: RDD[Int] = sc.makeRDD(List[Int]())

      val user = new user()

      rdd.foreach(
        //todo 源码:ClosureCleaner.clean(f, checkSerializable)
        num=>{
          println("age:" + user.age+num)
        }
      )

      sc.stop()
    }
  //这里可以选择是否进行序列化类
  class user extends {
    var age:Int= 30
  }
}

6.总结

在spark的scala程序中,我们都是定义的main方法

main方法中又定了在executor的方法

executor在使用main方法中的变量时,要进行要将main方法变量提高生命周期,

版本之前以匿名内部类的方法实现,在调用之前检查能够进行序列化传输

并编译成高声明周期的变量

称为闭包检查


文章作者: Jinxin Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jinxin Li !
  目录