美文网首页
scala-控制结构和函数

scala-控制结构和函数

作者: 奋斗的蛐蛐 | 来源:发表于2021-03-11 13:55 被阅读0次

    控制结构和函数

    if 表达式

    Scala中 if 表达式有返回值。如果if 和 else 的返回值类型不一样,那么就返回两个返回值类型公共的父类。

    /**
     * @description:
     * @date: 2020-09-22 20:13
     **/
    object IfDemo {
    
      def main(args: Array[String]): Unit = {
        val num = 20
        
        if (num > 20) "张三" else "李四"
        
        if (num > 20) 0 else if (num == 20) 1 else 0
    
        //因为if else 有返回值,那么可以直接将if else语句赋值给一个变量
        // if else 语句的返回值,不需要加return
        val name = if (num > 20) "张三" else "李四"
    
        //如果if else 语句中,两个返回值类型不一样
        //此时Scala会自动推断出两者的公共父类型,然后将公共父类型作为表达式的返回值类型
        var name2: Any = if (num == 20) "张三" else 100
    
        //如果if else 语句中,缺省else语句块,那么默认else的值就是Unit
        // Unit用()表示,类似Java中的void
        val name3 = if (num == 20) "王武"
        //name3 与 name4等同
        val name4 = if (num == 20) "王武" else ()
      }
    }
    

    for 表达式

    Scala中,for循环语法结构:for (i <- 表达式 / 集合),让变量 i遍历<-右边的表达式/集合的所有值。

    Scala为for循环提供了很多的特性,这些特性被称之为 for守卫式 或 for推导式。

    package hhb.cn.part02
    
    /**
     * @description:
     * Scala永远与Java相同的While 和 do While循环
     * 但是没有与Java for循环相对应的语法结果
     * Scala中 for( i <- 表达式或集合),让循环变量i遍历 <- 右边表达式或集合的所有值
     * 注意:循环变量i前面没有用val或者var来修饰,这个循环变量的类型是表达式或集合的元素类型
     * 循环变量的作用域一直持续到循环结束
     * @date: 2020-09-22 20:25
     **/
    object ForDemo {
    
      def main(args: Array[String]): Unit = {
        //for 基本结构,使用to实现左右两边闭合访问区间[1,10]
        for (i <- 1 to 10) {
          println(s"i = $i")
        }
        // for基本结果,使用until实现左闭右开的区间[0,10)
        for (i <- 1 until 10) {
          println(s"i = $i")
        }
        // 双重循环,相当于Java中的嵌套循环,条件之间用分号分割
        println("============双重循环=============")
        for (i <- 1 to 3; j <- 1 to 5) {
          println(i * j)
        }
        println("============循环中使用变量=============")
        for (i <- 1 to 4; j = 4 - i) {
          println(i * j)
        }
        println("============守卫式,增加if条件语句=============")
        //注意if前面没有分号
        for (i <- 1 to 10; j <- 1 to 10 if i == j) {
          println(s" i * j = $i * $j = ${i * j}")
        }
        println("============推导式,使用yield接受返回结果=============")
        // 如果for循环中的循环体是以yield开始,那么此循环会构造除一个集合,每次迭代生成集合中的一个值。
        //可以使用变量接受产生的新集合
        val result = for (i <- 1 to 5) yield i % 2
        result.foreach(println(_))
        println("============九九乘法表=============")
        for (i <- 1 to 9; j <- 1 to i) {
          print(s"$j * $i = ${j * i}\t")
          if (j == i) println()
        }
        println("============for循环中使用大括号=============")
        for {
          i <- 1 to 3
          from = 4 - i
          j <- from to 3
        }
          println(s" i = $i,j = $j")
        println("============for循环遍历字符串=============")
        val message = "scala"
        for (elem <- message) println(elem)
      }
    }
    

    while 表达式

    Scala提供了与 Java 类似的while和do...while循环。while语句的本身没有任何返回值类型,即while语句的返回结果是Unit类型的 () 。

    Scala内置控制结构特地去掉了 break 和 continue。

    特殊情况下如果需要终止循环,可以有以下三种方式:

    • 使用Boolean类型的控制变量
    • 使用return关键字
    • 使用breakable和break,需要导入scala.util.control.Breaks包
    package hhb.cn.part02
    /**
     * @description:
     * @date: 2020-09-23 10:50
     **/
    object WhileDemo {
      def main(args: Array[String]): Unit = {
        var num = 1
        while (num < 10) {
          println(s"num = $num")
          num += 1
        }
        println("============do……while===============")
        num = 1
        do {
          println(s"num = $num")
          num += 1
        } while (num < 10)
        println("============使用boolean终止循环===============")
        var flag = true
        num = 1
        while (flag) {
          println(s"num = $num")
          num += 1
          if (num == 5) flag = false
        }
        println("============使用break终止循环===============")
        // 使用breakable 和 break 终止循环,需要导入包
        import scala.util.control.Breaks._
        var res = 0
        breakable {
          for (i <- 1 until 10) {
            if (i == 5) break()
            res += i
          }
        }
        println(res) // 10
        println("============使用return终止循环===============")
        for (i <- 1 to 10) {
          if (i == 5) return
          println(s"i = $i")
        }
      }
    }
    

    Break 和continue

    scala> import scala.util.control.Breaks._
    import scala.util.control.Breaks._
    
    //break
    scala> breakable{
         | for(i <- 1 to 10) if(i == 5) break() else println(i)
         | }
    1
    2
    3
    4
    //continue
    scala> for(i <- 1 to 10){
         | breakable{
         |     if(i % 3 ==0) break() else println(i)
         |    }
         |}
    1
    2
    4
    5
    7
    8
    10
    

    函数

    函数.png

    函数体中最后一句为返回值的话,可以将return 去掉;如果一个函数体只有一句代码,大括号可以去掉;

    如果一个函数没有返回值,其返回类型为Unit , 并且 “=” 号可以去掉,这样的函数被称为过程;

    可以不声明函数的返回类型,返回类型可通过自动类型推断来完成,但递归函数的返回类型必须声明;

    备注:建议明确声明函数的返回值,即使为Unit

    package hhb.cn.part02
    
    /**
     * @description:
     * @date: 2020-09-23 11:13
     **/
    object FunctionDemo {
      def main(args: Array[String]): Unit = {
        println(add(1, 3))
        println("计算阶乘 : " + factorial(5))
        println("斐波那契数列 : " + fibonacci(7))
        println("无返回值 : " + getSum(1, 1))
    
        //调用函数式使用函数参数的默认值
        println("默认值 : " + add2())
        //给函数中参数重新赋值
        println("默认值 : " + add2(1, 2))
        //不按照参数顺序传递值,而是使用带名参数的方式传值
        println("默认值 : " + add2(y = 60, x = 50))
    
        println("变长参数 : " + addSum(1))
        println("变长参数 : " + addSum(1, 2, 3))
        println("变长参数 : " + addSum(1, 2, 3, 4, 5))
        //使用    : _*   告诉编译器这个参数被当作参数序列来处理
        println("变长参数 : " + addSum(1 to 10: _*))
      }
    
      /**
       * 定义函数的语法:def 函数名(参数列表):返回值类型={函数体}
       * 函数体最后一条语句的返回值作为整个函数的返回值,返回值不需要使用return关键值
       * 也可以不声明返回值类型,Scala会自动根据最后一条语句返回值类型推断出函数的返回值类型
       * 但是,如果函数是递归函数,其返回值类型必须声明
       *
       * @param num1 第一个参数
       * @param num2 第二个参数
       * @return
       */
      def add(num1: Int, num2: Int) = {
        num1 + num2
      }
    
      /**
       * 使用递归计算阶乘
       *
       * @param num
       * @return
       */
      def factorial(num: Int): Long = {
        if (num <= 1) 1
        else num * factorial(num - 1)
    
      }
    
      /**
       * 通过递归实现斐波那契数列:1,1,2,3,5,8,13……
       *
       * @param num
       * @return
       */
      def fibonacci(num: Int): Long = {
        if (num == 1 || num == 2) 1
        else fibonacci(num - 1) + fibonacci(num - 2)
      }
    
      /**
       * 如果函数没有返回值,返回值类型为Unit,类似于Java的void,类型以及等号可以省略
       * 在Scala中,没有返回值的函数称为过程
       *
       * @param x
       * @param y
       */
      def getSum(x: Int, y: Int) {
        println(x + y)
      }
    
      /**
       * 函数中的参数可以有默认值,称为默认函数
       *
       * @param x
       * @param y
       * @return
       */
      def add2(x: Int = 10, y: Int = 20): Int = {
        x + y
      }
    
      /**
       * 变长参数:参数类型右边加上*号
       * 变长参数一个方法只能出现一个,且在最后,类似Java可变参数
       * 在Spark源码中,有大量的变长参数
       *
       * @param nums
       * @return
       */
      def addSum(nums: Int*): Int = {
        nums.sum
      }
    }
    

    懒值

    当 val 被声明为lazy时(var不能声明为lazy),它的初始化将被推迟,直到首次对此取值,才会被初始化.适用于初始化开销较大的场景。

    • 打开数据库连接
    • 提升某些特定模块的启动时间
    • 确保对象中的某些字段能优先初始化
    /**
     * @description:在Scala中提供了Lazy的特性
     * 如果将一个变量声明为一个Lazy,那么只有第一次使用这个变量是,变量对应的表达式才会发生计算。
     * 这中特性对于特别耗时的计算操作,特别有用
     * 比如初始化开销比较大的场景 ,对文件进行IO、进行网络IO的操作等
     * @date: 2020-09-23 13:57
     **/
    object LazyDemo {
    
      def main(args: Array[String]): Unit = {
        // 此时启动main方法,直接报错,提示java.io.FileNotFoundException: /User/test.scala (No such file or directory)
        //    val file = scala.io.Source.fromFile("/User/test.scala")
    
        //此时启动main方法,不会报错,因为根本没有加载文件,只有有调用file变量的时候,才会加载文件
        lazy val file = scala.io.Source.fromFile("/User/test.scala")
        println("OK!")
        //调用file
        file.getLines().size
      }
    }
    

    文件操作

    导入scala.io.Source后,可引用Source中的方法读取文本文件的内容.如果要将文件内容转数组,直接调用toArray。

    package hhb.cn.part02
    
    import java.io.PrintWriter
    
    import scala.io.Source
    
    /**
     * @description:I/O
     * I/O操作是一门编程语言的重要内容
     * 相比于Java语言中的IO类,Scala中的IO类较少,比较常用的是Source这个类
     * 在Scala中,更多的是调用Java中的IO或通过Java中的IO进行相对应的封装来实现IO操作
     * @author: huanghongbo
     * @date: 2020-09-23 14:05
     **/
    object FileDemo {
    
      def main(args: Array[String]): Unit = {
        readTextFile
        readNetSource
        writeTxt
      }
    
      /**
       * 读取文本文件
       */
      def readTextFile: Unit = {
        val source = Source.fromFile("/Users/baiwang/myproject/scala/src/test.txt")
        val values: Iterator[String] = source.getLines()
        for (value <- values)
          println(value)
        //关闭IO
        source.close()
      }
    
      /**
       * 读取网络资源
       */
      def readNetSource: Unit = {
        val source = Source.fromURL("https://www.baidu.com")
        //将资源转换成字符串
        val value = source.mkString
        println(value)
        source.close()
      }
    
      /**
       * 写入文本文件
       * Scala中,没有内建的对应写入文件的支持,需要使用java.io.PrintWriter来实现
       */
      def writeTxt: Unit = {
    
        val writer = new PrintWriter("/Users/baiwang/myproject/scala/src/write.txt")
        for (i <- 1 to 10) {
          //写入文件内容
          writer.println(s"i = $i")
          //刷新缓冲区
          writer.flush()
        }
        writer.close()
      }
    }
    

    方法的调用方式

    • 后缀调用法

      Math.abs(-10)

    • 中缀调用法

      Math abs -10

    • 花括号调用法

      方法只能有一个参数

      Math.abs{-10}

    • 无括号调用法

      如果方法没有参数,可以省略方法名后面的括号

    image.png
    def test(): String = ""
    

    相关文章

      网友评论

          本文标题:scala-控制结构和函数

          本文链接:https://www.haomeiwen.com/subject/nyziqltx.html