Scala学习视频心得(三)函数、流程控制

1、流程控制

1)if…else

    //1、单分支的情况
    /*println("请输入年龄")
    val age: Int = StdIn.readInt()
    if(age<18){
      println("童年")
    }*/

    //2、双分支
    /*println("请输入年龄")
    val age: Int = StdIn.readInt()
    if(age<18){
      println("童年")
    } else{
      println("成年")
    }*/

    //3、多分支
    /*println("请输入年龄")
    val age: Int = StdIn.readInt()
    if(age<18){
      println("童年")
    } else if(age>=18 && age<=40){
      println("成年")
    }else{
      println("老年")
    }*/

    //4、分支语句带返回值 返回类型一致
    /*println("请输入年龄")
    val age: Int = StdIn.readInt()
    //分支语句是有返回值的,具体返回什么,和满足条件的分支语句中的最后一行代码有关
    val res: String = if (age < 18) {
      "童年"
    } else if (age >= 18 && age <= 40) {
      "成年"
    } else {
      "老年"
    }
    println(res)*/


    //5、分支语句带返回值 返回类型不一致
    /*println("请输入年龄")
    val age: Int = StdIn.readInt()
    //如果每一个分支块返回的类型不一致,取他们共同的祖先类型
    val res:Any = if (age < 18) {
      "童年"
    } else if (age >= 18 && age <= 40) {
      "成年"
    } else {
      100
    }
    println(res)*/

    //案例:通过if..。else模拟三元运算符实现 res=条件表达式?值1:值2
    println("请输入年龄")
    val age: Int = StdIn.readInt()
    //如果分支代码块中,只有一行代码,那么花括号可以省略
    var res = if (age<18) "童年" else "成年"

2)for循环控制

    /**
      * 1、对范围数据进行遍历 to 前后闭合
      */

    //for(int i:1 to 10)错误
    //1 to 10 表示产生从1到10的集合
    //for (i:Int <- 1.to(10))
    //在声明变量的时候,类型可以省略,因为编译器根据集合中的数据,推导出变量的类型
    for (i: Int <- 1 to 10) {
      println(i) //1 2 3 4 5 ...10
    }

    println("==========================")

    /**
      * 2、对范围数据进行遍历 until 前闭合后开的范围
      */
    for (i <- 1 until 10) {
      println(i) //1 2 3 4 5 ...9
    }

    println("==========================")

    /**
      * 3、循环守卫
      * 在scala语言中,没有continue和break关键字
      * 通过if来判断模拟continue跳出本次循环
      * 通过调用方法模拟break跳出整个循环功能
      */
    for (i <- 1 to 5) {
      if (i != 3) { //利用if判断跳出3
        println(i) //1 2 4 5
      }
    }

    //循环守卫
    for (i <- 1 to 5; if i != 3) println(i)

    println("==========================")

    /**
      * 4、循环步长 by
      * 步长不能为0
      */
    //要求对1到10中的奇数进行遍历
    for (i <- 1 to 10 by 2) println(i)
    //利用循环步长另类倒序10->1
    for (i <- 10 to 1 by -1) println(i)


    /**
      * 5、循环嵌套
      */
    for (i <- 1 to 3) {
      for (j <- 1 to 3) {
        println("i=" + i + ",j=" + j)
      }
    }

    println("======================")
    //九九乘法表
    for (i <- 1 to 9) {
      for (j <- 1 to i) {
        print(s" ${j} * ${i} = ${i * j} ")
      }
      println("")
    }

    //同理
    /*for (i <- 1 to 9;j <- 1 to i) {
      print(s" ${j} * ${i} = ${i * j} ")
      if(i==j){
        println()
      }
    }*/

    /**
      * 6、循环引入变量
      */

    for {
      i <- 1 to 5;
      j = 10 - i
    } {
      println("i=" + i + ",j=" + j)
    }

    println("=" * 50)

    //打印九层妖塔(等腰三角形)
    for {i <- 1 to 9; j = 2 * i - 1; z = 9 - i} println(" " * z + "*" * j)


    /**
      * 7、循环返回值
      * 将遍历过程中处理的结果返回到一个新Vector集合中,使用yield关键字。
      */
    val res: immutable.IndexedSeq[Int] = for (i <- 1 to 5) yield i * 2
    println(res)

    /**
      * 8、倒序打印
      * 底层调用的是reverse方法
      */
    for (i <- 1 to 10 reverse) {
      println(i)
    }

3)while循环

    /**
      * 1、while
      * while循环是先判断,再执行
      */
    var a: Int = 5
    while (a >= 1) {
      println("友培666!")
      a -= 1
    }

    /**
      * 2、do...while
      * do..while循环是先执行,再判断
      */
    var b: Int = 5
    do {
      println("友培真棒!")
      b -= 1
    } while (b >= 1)

4)循环中断★

Scala内置控制结构特地去掉了break和continue,是为了更好的适应函数式编程,推荐使用函数式的风格解决break和continue的功能,而不是一个关键字。Scala中使用breakable控制结构来实现break和continue功能。

    /**
      * 循环中断
      *
      * 在scala语言中,没有break和continue关键字
      *     通过在循环体中加入条件判断 实现continue效果
      *
      */

    /**
      * 1、利用抛出异常的想法
      */
    /*
    try{
      for (i <- 1 to 5){
        if(i == 3){
          //抛出异常,跳出整个循环
          throw new RuntimeException
        }
        println(111)
      }
    }catch {
      //捕获异常,并对其进行处理
      case e:Exception=>
    }
    */


    /**
      * 2、利用Breaks类
      */
	/*    
	//标记当前循环是可中断的
    Breaks.breakable(
      for (i <- 1 to 5){
        if(i == 3){
          //跳出整个循环
          Breaks.break()
        }
        println(111)
      }
    )
    */

    //3、导入静态类
    breakable(
      for (i <- 1 to 5){
        if(i == 3){
          //跳出整个循环
          break
        }
        println(111)
      }
    )

    println("这是循环之外的代码")

2、函数

1)函数定义

	//1、函数:无参无返回值
    def f1()={
      println("无参,无返回值")
    }
    f1()


    //2、无参,有返回值
    def f2():Int={
      println("无参,有返回值")
      return 10
    }
    println(f2())


    //3、有参,无返回值
    def f3(name:String)={
      println("有参,无返回值")
    }
    println(f3("xiaoyoupei"))


    //4、有参,有返回值
    def f4(name:String):String={
      println("有参,有返回值")
      return "hello-->" + name
    }
    println(f4("xiao"))

    //5、多参,无返回值
    def f5(name:String,age:Int)={
      println("多参,无返回值")
      println(s"${name}今年${age}岁了")
    }
    println(f5("xiao",21))


    //6、多参,有返回值
    def f6(a:Int,b:Int):Int={
      println("多参,有返回值")
      return a + b
    }
    println(f6(10,20))

2)函数参数

	//1、可变参数 底层使用集合来接收参数
    def f1(s : String *)={
      println(s)
    }
    f1()  //List()
    f1("aaa","bbb")  //WrappedArray(aaa, bbb)

    //2、如果在参数列表中存在多个参数,那么可变参数应该放在最后
    //在一个参数列表中,至多有一个可变长参数
    def f2(s1:String,s2:String*)={

    }

    //3、参数默认值,一般将有默认值的参数放在参数列表后面
    def f3(name:String="xiao")={
      println(name)
    }
    f3()
    f3("youpei")

    //4、带名参数
    def f4(name:String="liyan",sex:String)={
      println(name+":::"+sex)
    }
    f4("xiao","man")
    f4(sex="woman")

3)函数至简原则

    /**
      * 函数正常的定义与调用
      */

    def sayHi(name:String):String={
      return name
    }

    println(sayHi("xiaoyoupei"))

    //1、return可以省略,scala会使用函数体的最后一行代码作为返回值
    def f1(name:String):String={
      name
    }
    println(f1("xiaoyoupei"))

    //2、函数只有一行代码,花括号可以省略
    def f2(name:String):String=name
    println(f2("xiao"))

    //3、返回值类型可以推断,那可以省略(:和返回值类型一起省略)
    def f3(name:String)=name
    println(f3("xiao"))

    //4、如果有return,则不能省略返回值类型,必须指定
    def f4(name:String):String= {
      return name
    }
    println(f4("xiao"))

    //5、如果函数声明unit,即使函数体中使用return关键字也不起作用
    def f5(name:String):Unit={
      return name
    }
    println(f5("xiao"))

    //6、scala如果期望是无返回值类型,可以省略等号 这种写法称为过程
    def f6(name:String){
      name
    }
    println(f6("xiao"))

    //7、如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
    def f7():Unit={
      println("hello")
    }
    f7
    f7()

    //8、如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
    def f8:Unit={
      println("hello")
    }
    f8//f8()括号必须省略

    //9、如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
    //函数类型 ff:(参数列表声明)=>返回值

    def f10 (s:String):Unit={
      println(s)
    }

    def f9(f:(String)=>Unit):Unit={
      f("xiao")
    }

    f9(f10)

    //上面的写法过于繁琐,每次调用f9的时候还得调用f10
    //可以调用匿名函数 通过Lambda表达式实现 (参数列表)->{函数体}
    f9((s:String)=>{println(s)})

    //1、参数类型可以省略,会根据形参自动推导
    f9((s)=>{println(s)})

    //2、类型省略后,发现只有一个参数,则圆括号可以省略,其他情况:没有参数和参数超过1的永远不能省略圆括号
    f9(s=>{println(s)})

    //3、匿名函数如果是一行,则大括号也可以省略
    f9((s)=>println(s))

    //4、如果参数只出现一次,则参数省略用_(下划线)代替
    f9(println(_))

    //如果在进行println输出的时候,可以推断是一个函数,那么下划线可以省略
    f9(println)

4)高阶函数

① 函数作为值传递

	/**
      * 函数作为值传递
      */
    //函数的正常声明与调用
    def foo(): Int = {
      println("foo")
      10
    }

    //将foo函数的执行结果赋值给res变量
    val res: Int = foo()
    println(10)

    //函数作为值进行传递,语法:在函数名称的后面加上+ 空格 加下划线
    //注意:将foo函数作为一个整体,赋值给f变量,f是函数类型 ()=>Int
    val f: () => Int = foo _

    //这个时候,f是一个函数,如果要想运行f函数的话,必须得加()
    println(f) //输出的结果为<function0>

    println(f()) //输出的结果为函数执行结果

    //var ff = foo //将函数执行结果赋值给ff
    //var ff = foo _ //将函数本身作为值赋给ff
    var ff: () => Unit = foo //将函数本身作为值赋给ff
    println(ff)

    println("=" * 100)

    /**
      * 函数可以作为参数,进行传递(大多数情况都是通过匿名函数的形式)
      */


    //定义一个函数calculator,该函数接收一个函数类型的参数op,定义了对两个整数要进行什么样的操作
    def calculator(a: Int, b: Int, f1: (Int, Int) => Int): Int = {
      f1(a, b)
    }

    //定义一个函数f1,完成两个整数的加法运算
    def f1(a: Int, b: Int): Int = {
      a + b
    }

    println(calculator(10, 20, f1))

    //利用匿名函数的方式
    println(calculator(50, 20, (a: Int, b: Int) => {
      a - b
    }))

    println("=" * 100)

    /**
      * 函数作为返回值返回 -- 函数的嵌套
      */
    def ff1(): () => Unit = {
      def ff2(): Unit = {
        println("ff2被调用了")
      }
      //将ff2作为返回值返回给ff1
      ff2
    }

    //fff就是ff2
    //val fff = ff1()
    //fff()
    ff1()()

② 函数作为参数传递

	/**
      * 将函数作为参数传递
      * 扩展函数的功能
      * 提高函数的灵活度
      */
    //需求:提供一个函数,对数组中的元素进行处理,处理完毕后返回一个新的数组 目前处理方式:元素 + 1
    //创建一个数据对象 val arr:Array[Int] = Array(1,2,3,4)

    def operationArray(arr: Array[Int], op: Int => Int): Array[Int] = {
      //遍历数组中的元素
      for (elem <- arr) yield op(elem)
    }

    def op(elem: Int): Int = {
      elem + 1
    }

    //调用函数,实现+1功能
    val newArray: Array[Int] = operationArray(Array(1,2,3,4),op)

    //打印输出,mkString:用指定的字符串连接数组中的元素,形成一个新的字符串
    println(newArray.mkString(","))

    //通过匿名函数,对数组元素*3
    operationArray(Array(1,2,3,4),_*3)

5)函数的柯里化和闭包

/*def f1(): (Int => Int) = {
      var a: Int = 10

      def f2(b: Int): Int = {
        a + b
      }

      f2 _
    }

    //执行f1函数返回f2,将返回的f2赋值给ff变量
    val ff: Int => Int = f1()

    //闭包:内层函数f2要访问外层函数f1局部变量a,当外层函数f1执行结束后,f1会释放内存,但是会自动延长f1函数的局部变量的生命周期,
    //      和内层函数f2形成一个闭合的效果,我们称这种闭合的效果称之为闭包
    //  闭包 = 外层函数的局部变量 + 内层函数
    //调用ff函数,其实就是调用f2
    println(ff(20))

    //也可以直接通过如下方式调用
    println(f1()(20))
*/
    println("=" * 100)

    //以上的代码可以转换为以下代码
    def f1(): (Int) => Int = {
      var a: Int = 10

      def f2(b: Int): Int = {
        a + b
      }

      f2 _
    }

    def f3() = {
      var a: Int = 10
      (b: Int) => a + b
    }

    /**
      * 柯里化
      */
    //将一个函数的一个参数列表的的多个参数,拆分成为多个参数列表
    def f4()(b: Int) = {
      var a: Int = 10
      a + b
    }

    //f4在执行的时候会转为以下结构
    def f5() = {
      var a: Int = 10
      (b: Int) => a + b
    }

6)递归

/**
      * 递归调用
      */
  }

  def digui(n:Int):Int={
    if(n==1) {
      return 1
    }
    n * digui(n-1)
  }

  digui(2)

7)控制抽象

/**
      * 控制抽象
      *
      * 值调用 :将函数计算后的值进行传递
      *
      * 名调用 :传递的是代码块
      */
    //值调用
    //数据类型 Int,String,函数 参数类型=>返回值,代码块
    //a : => Int 返回值是Int类型的代码块
    def foo(a : => Int):Unit={
      println(a)
      println(a)
    }
    def f():Int={
      println("f...")
      10
    }

    foo(f) //结果为:f... 10 f... 10


    def f1(ss: =>Unit):Unit={
      ss
    }

    f1(
      {
        println("xiao")
      }
    )
  }

8)自定义函数,实现while循环

	/**
      * 自定义函数,实现while循环
      */

    //while循环
    /*var n =10
    while(n>=1){
      println(n)
      n-=1
    }*/

    //使用柯里化 实现 mywhile(循环条件)(循环体)
    /**
      * 柯里化的好处:
      * 1、将一个参数列表的多个参数,拆分成多个参数列表,这样参数所表示的含义:清晰、明确
      * 2、简化闭包的编写
      */
    def mywhile(condition: => Boolean)(op: => Unit): Unit = {
      if (condition) {
        op
        mywhile(condition)(op)
      }
    }

    var n = 10
    mywhile(n >= 1) {
      println("mywhile-->" + n)
      n -= 1
    }

    //直接使用普通的函数,实现while循环
    def mywhile1(condition: => Boolean, op: => Unit): Unit = {
      if (condition) {
        op
        mywhile1(condition, op)
      }
    }

    var n1 = 10
    mywhile1(n1 >= 1, {
      println("mywhile1-->" + n1)
      n1 -= 1
    })

    //使用闭包的形式,实现mywhile循环
    def mywhile2(condition: => Boolean): (=> Unit) => Unit = {
      //内层函数表示循环体
      def ff(op: => Unit): Unit = {
        if (condition) {
          op
          mywhile2(condition)(op)
        }
      }

      ff _
    }

    var n2 = 10
    mywhile2(n2 >= 1) {
      println("mywhile2-->" + n2)
      n2 -= 1
    }

9)惰性函数

	/**
      * 惰性加载
      */

    //lazy惰性加载,函数的执行会往后延,什么时候用到结果,什么时候执行函数
    lazy val res: Int = sum(2,3)
    println("1.------------------")

    println("2."+res)

  }

  def sum(a: Int, b: Int): Int = {
    println("3.sum被执行")
    a + b
  }
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页