3.Scala-控制结构和函数

第3章 控制结构和函数

Java 中把表达式和语句当成两个不同的东西,表达式有值,语句没有值,
只是控制结构。在 Scala 中,几乎所有语法结构都有值。

3.1 If else 表达式

scala> val x = 5
x: Int = 5

scala> val s = if( x > 0 ) 1 else -1
s: Int = 1
S 为什么会有值?
If 语句的返回类型取决于最后一条语句。语句后面的分号不是必须的。
Scala 没有三元运算符,不需要。
 
 
  If 表达式会有一个返回值类型,如果 if 或者 else 返回的类型不一样,就
返回 Any 类型(所有类型的公共超类型)。 
scala> val s1 = if( x > 0) "hello" else -1
s1: Any = hello

scala> val s3 = if ( x < 0 ) "hello"
s3: Any = ()
 
  如果缺少一个判断,什么都没有返回,但是 Scala 认为任何表达式都会
有值,对于空值,使用 Unit 类,写做()【叫做无有用占位符,相当于 java
中的 void】 
scala> val s4 = if(x < 0 ) "hello" else ()
s4: Any = ()
注:行尾的位置不需要分号,只要能够从上下文判断出语句的终止即可。但是如果
在单行中写多个语句,则需要分号分割。在 Scala 中,{}快包含一系列表达
式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。 

3.2 while 表达式

  Scala 提供和 Java 一样的 while 和 do 循环,与 If 语句不同,While 语句
本身没有值,即整个 While 语句的结果是 Unit 类型的()。 
while (n > 0) { 
    r = r * n
    n -= 1
    println(r)
}
do{
    r = r * n
    n -= 1
    println(r)
}while(n > 0)
注:scala 并没有提供 break 和 continue 语句来退出循环,如果需要 break,可以
通过几种方法来做 1、使用 Boolean 型的控制变量 2、使用嵌套函数,从函数中
return 3、使用 Breaks 对象的 break 方法。 
//循环的终止
import scala.util.control.Breaks
val looper = new Breaks() //括号可以省略

var count = 0
looper.breakable{         // . 可以替换成空格
  while(count <= 100){
    count += 1
    println(count)
    if(count == 10){
      looper.break()
    }
  }
//多重while循环的终止
val whileLooper1 = new Breaks
val whileLooper2 = new Breaks

whileLooper1.breakable{
  while (true){
    count += 1
    if(count == 10){
      whileLooper1.break()
    }
    
    whileLooper2.breakable{
      while (true){
        if(count == 20){
          whileLooper2.break()
        }
      }
    }
    
  }
}

3.3 for 表达式 

  Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for
循环的特性被称为 for 推导式(for comprehension)或 for 表达式(for
expression)。
 
 
  推导式一词起源于函数式编程。 
像 变量名 <- 集合 这样的表达式也被称为生成器表达式,该表达式会
基于集合生成单独的数值。 
//多重for循环
for(i <- 1 to 3; j <-1 to 3){
  println(i + "----" + j)
  println()
}
//输出10 9 8 7 ... 1
for(i <- Range(10, 0, -1)){
  println(i)
}


//输出1~9
for(i <- 1 until 10){
  println(i)
}
  保护式,也叫守卫,可以添加一个或者多个守卫,不需要 continue 语句

 

//实现1~10的输出,只输出偶数
for (i <- 1 to 10 if i % 2 == 0){
  println(i)
}

  For 推导式可以引入变量 

//在for循环中添加变量表达式
for(i <- 1 to 10; j = 10 - i; m = j * i){
  println("j:" + j)
  println("m:" + m)
}
  需要返回值怎么办?
  使用 yield 关键字便能在 for 表达式中生成新的集合。for-yield 表达式所
生成的集合类型将根据被遍历的集合类型推导而出。 

 

scala> val forResult = for (i <- 1 to 10) yield i
forResult: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 尖叫提示:{}和()对于 for 表达式来说都可以。for 推导式有一个不成文的约定:当
for 推导式仅包含单一表达式时使用原括号,当其包含多个表达式时使用大括
号。值得注意的是,使用原括号时,早前版本的 Scala 要求表达式之间必须
使用分号。

 

//使用花括号作为for循环的条件包裹
for{
  i <- 1 to 3
  m = i * 2
}
  println(m) //需要使用具体的逻辑

Scala 随堂笔记

一、变量的声明
    ** val:初始化后不能被再次赋值
    ** var:初始化之后可以多次复制
    ** if else:有返回值,如果多个逻辑控制代码块,返回不同的值,则返回为:Any
    ** 循环:
        ** while
            -- 返回值类型为Unit -> ()
            -- break的用法
        ** for
            -- 基本形式
            -- 守卫
            -- 表达式
            -- 多个循环体放在同一个参数体内
            -- 输出遍历元素到一个集合中并返回:yeild i
            -- {}花括号形式,用的不多

3.4 函数

  Scala 提供了很多函数,如果 math 函数,Java 中通常通过静态方法来模
拟。函数定义如下:
 
  def 函数名(参数名:类型…)[: 返回类型] = 函数体
比如:
    def play(a1 : Int, a2 : Int) : String = {
      (a1 + "," + a2) }
    def play(a1 : Int, a2 : Int)
= { //返回值可以省略
      a1 + a2 }

    def paly(a1 : Int, a2 : Int) = a1 + a2

    def paly = 1;
 
  //标准形式
    def play1(a1: Int, a2: Int): String = {
      String.valueOf(a1 + a2)
    }
    println(play1(10, 20))

    //省略返回值形式(返回的是循环中最后一行的值)
    def play2(a1: Int, a2: Int) = {
      a1 + a2
    }
    println(play2(10, 10))


    //省略花括号形式
    def play3(a1: Int, a2: Int) = a1 + a2
    println(play3(5, 5))


    //返回Unit类型的函数
    def play4(a1: String) : Unit = {
      println(a1)
    }


    //返回Unit类型的函数,但是没有显示指定返回类型。(当然也可以返回非Unit类型的值)
    def play5(a1: String) = {
      println(a1)
    }


    //返回类型有多种可能,此时也可省略Unit
    def play6(a1: String) = {
      if(a1.length >= 3)
        a1 + "hello"
      else
        3
    }


    //可选参数
    def play7(a1: Int, a2: Int = 10) = {
      a1 + a2
    }
    println(play7(1))


    //变长参数
    def play8(args: Int*) = {
      for(i <- args){
        println(i)
      }
    }
    play8(1,2,3,4,5)


    //递归函数:在使用的时候必须要有明确的返回值类型
    //递归实现阶乘
    def factorial(n : Int) : Int = {

      if(n == 1)
        n
      else
        factorial(n - 1) * n

    }
    println(factorial(3))
 
注:1、Scala 可以通过=右边的表达式 推断出函数的返回类型。如果函数体需要
多个表达式,可以用代码块{}。
2、可以把 return 当做 函数版本的 break 语句。
3、递归函数一定要指定返回类型。
4、变长参数通过* 来指定,所有参数会转化为一个 seq 序列
5、_* 告诉编译器 Range 当做参数序列化处理。
6、Head 是获得首元素,tail 是获取剩下元素的序列。

3.5 过程

我们将不返回值得函数叫做过程,返回类型是 Unit,他是没有=号的。

1)定义过程示例1:(显示的返回值类型为Unit)

def shout1(content: String) : Unit = {
  println(content)  
}

2)定义过程示例2:(隐式的返回值类型是Unit)

def shout1(content: String) = {
  println(content)  
}

3)定义过程示例3:(没有 = 号)

def shout1(content: String) {
  println(content)  
}

 

3.6 匿名函数

    //匿名函数
    /*
      * 1、匿名函数右边的函数体应该使用 => 符号来指定
      * 2、匿名函数的函数体,可以是一个包含多行代码的代码块
      * 3、函数的类型,为参数个数的类型
     */
    val play10 = () => 0
    println(play10) //<function0> 表示传参个数为0
    println(play10()) //0

    val play11 = (a1 : Int) => 0
    println(play11) //<function1> 表示传参个数为1

    val play12 = (a1 : Int, a2 : Int) => {
      a1 + a2
      a2 - 10 + a1
    }
    println(play12) //<function2>
    println(play12(10, 20)) //20

3.7 懒值

当 val 被声明为 lazy 时,他的初始化将被推迟,直到我们首次对此取
值。
懒值使用注意:
1) 用于初始化开销比较大的语句。
2) 可以解决循环依赖问题。
3) 是开发懒数据结构的基础。 

1)lazy 示例:通过 lazy 关键字的使用与否,来观察执行过程

    def play1(a1: Int) = {
      println("play1方法被执行," + "a1:" + a1)
      a1
    }

    lazy val l1 = play1(10)
    val l2 = play1(20)
    println("l1变量定义完毕")
    println(l1)

    /*
    结果:
    play1方法被执行,a1:20
    lazy变量定义完毕
    play1方法被执行,a1:10
    10
     */

3.8 异常

  当碰到异常情况时,方法抛出一个异常,终止方法本身的执行,异常传
递到其调用者,调用者可以处理该异常,也可以升级到它的调用者。运行系
统会一直这样升级异常,直到有调用者能处理它。 如果一直没有处理,则终
止整个程序。
 
  Scala 的异常的工作机制和 Java 一样,但是 Scala 没有“受检”异常,你
不需要声明说函数或者方法可能会抛出某种异常。受检异常在编译器被检
查,java 必须声明方法所会抛出的异常类型。
 
  抛出异常:用 throw 关键字,抛出一个异常对象。所有异常都是
Throwable 的子类型。throw 表达式是有类型的,就是 Nothing,因为 Nothing
是所有类型的子类型,所以 throw 表达式可以用在需要类型的地方。 
//并不像 Java 代码那样,需要声明方法会抛出异常,这给程序员省去理论很多烦恼。
def divide(x: Int, y: Int): Int = {
    if (y == 0) throw new Exception("Divide by zero")
    else x / y
}
  捕捉异常:
  在 Scala 里,借用了模式匹配的思想来做异常的匹配,因此,在 catch 的
代码里,是一系列 case 字句。
  异常捕捉的机制与其他语言中一样,如果有异常发生,catch 字句是按次
序捕捉的。因此,在 catch 字句中,越具体的异常越要靠前,越普遍的异常越
靠后。 如果抛出的异常不在 catch 字句中,该异常则无法处理,会被升级到
调用者处。
  异常捕获通常采用模式匹配的语法: 
try { 
 process(in)
} catch { 
 case ex: IOException => println(ex)
} finally { 
 in.close()}
  finally 字句用于执行不管是正常处理还是有异常发生时都需要执行的步
骤,一般用于对象的清理工作。 
注:1、Throw 的类型为 Nothing,存在 exception 的 if 语句类型返回类型。
object ExceptionSyllabus {

  def divider(x: Int, y: Int): Float = {

    if(y == 0) throw new Exception("0 不能作为除数")
    else x/y

  }

  def main(args: Array[String]): Unit = {

    try {
      println(divider(10, 0))
    } catch {
      case ex:Exception => println("成功捕获异常" + ex.getMessage)
//      case ex:Throwable => println("成功捕获异常" + ex.getMessage)
    } finally {}

  }

}
原文地址:https://www.cnblogs.com/LXL616/p/11105476.html