zoukankan      html  css  js  c++  java
  • 快学Scala 2

    控制结构和函数

    1.在Scala中,几乎所有构造出来的语法结构都有值。这个特性是为了使得程序更加精简,也更易读。

      (1)if表达式有值

      (2)块也有值——是它最后一个表达式的值

      (3)Scala的for循环就像是“增强版”的Java for循环

      (4)分号(在绝大多数情况下)不是必须的

      (5)void类型是Unit

      (6)避免在函数定义中使用return

      (7)注意别在函数式定义中漏掉了=

      (8)异常的工作方式和Java中基本一样,不同的是catch语句中使用“模式匹配”

      (9)Scala没有受检异常

    2.条件表达式

      在Scala中if/else表达式有值,这个值就是跟在if或else之后的表达式的值。例如:

        if(x > 0) 1 else -1

      可以将if/else表达式的值赋值给变量:

        val s = if(x > 0) 1 else -1

      这与如下语句的效果一样:

        if(x > 0) s = 1 else s = -1

      不过第一种写法给号,因为它可以用来初始化一个val;而第二种写法中,s必须是var

      Scala中每个表达式都有一个类型。例如,表达式 if(x > 0) 1 else -1的类型是Int,因为两个分支的类型都是Int。混合类型表达式,比如if(x > 0) "positive" else -1,上述表达式的类型是另个分支类型的公共超类型。java.lang.String和Int的公共超类型叫做Any。

      如果else部分缺失了,比如:if(x > 0) 1,那么有可能if语句没有输出值。但是在Scala中,每个表达式都应该有某种值。解决方案是引入一个Unit类,写作()。不带else的if语句等同于:if(x > 0) 1 else ()

      把()当做表示“无有用值”的占位符,将Unit当做Java中的void。

      Scala没有switch语句,不过它有一个强大得多的模式匹配机制。现阶段,用一系列的if语句就好。

    3.REPL比起编译器来更加“近视”——它在同一时间只能看到一行代码。可用花括号:

      if(x > 0)  {1

      } else if(x == 0) 0 else -1

    只有在REPL中才会有这个顾虑。在REPL中粘贴成块代码,可用使用粘贴模式。键入:       :paste  把代码块粘贴进去,然后按下Ctrl+D。这样REPL就会把代码块当做一个整体来分析。

    4.语句终止

      在Scala中——与JavaScript和其他脚本语言类似——行尾的位置不需要分号。不过,如果你想要在单行中写下多个语句,就需要将它们以分号隔开。例如:

        if(n > 0) { r = r * n; n-=1}

      如果写较长的语句,需要分两行来写,就要确保第一行以一个不能用来做语句结尾的符号结尾。通常来说一个比较好的选择是操作符:

        s = s0 + (v- v0) * t + //+告诉解析器这里不是语句的末尾

          0.5 * (a - a0) * t * t

       如果倾向于使用分号,用就是了——他们没啥坏处。

    5.块表达式和赋值

      在Java中,语句块是一个包含于{}中的语句序列。在Scala中,{}快包含一系列表达式,其结果也是一个表达式。块中最后一个表达式的值就是块的值。

      这个特性对于val的初始化需要很多步完成的情况很有用。例如:

        val distance = { val dx = x - x0; val dy = y - y0;sqrt(dx * dx, dy * dy) }

      在Scala中,赋值动作本身是没有值的——或者,更严格地说,它们的值是Unit类型的。

        一个以赋值语句结束的块,比如{r = r * n; n-=1 }的值是Unit类型的。当我们定义函数时需要意识到这一点。

    6.输入和输出

      如果要打印一个值,用print或者println函数。另外,还有一个带有C风格格式化字符串的printf函数:

        printf("Hello",  %s! You are %d old. ", "Fred", 42) //  Hello,  Fred! You are 42 old.

      用readLine函数从控制台读取一行输入。也可以用readInt、readDouble、readByte、readShort、readLong、readFloat、readBoolean、readChar。不过,readLine带一个参数作为提示字符串:

        val name = readLine(”Your name:”)

        print(“Your age: ”)

        val age = readInt()

        printf("Hello, %s! Next Year, you will be %d . , name, age + 1)

    7.循环

      Scala拥有与Java和C++相同的while和do循环。例如:

        while(n > 0) {

          r = r * n;

          n -=1;

        }

      Scala没有与for(初始化变量;检查变量是否满足条件;更新变量)循环直接对应的结构。如果需要这样的循环,有两种选择:一是使用while循环,二是使用如下for语句:

        for(i  <-  表达式)  让变量i遍历 <- 右边的表达式的所有值。至于这个遍历具体如何执行,则取决于表达式的类型。对应Range而言,这个循环会让i一次取得区间中的每个值。

      例如:

        for(i <- 1 to n)

          r = r * i

      遍历数组和字符串时,需要0到n-1的区间,可以使用until方法而不是to方法。util方法返回一个并不包含上限的区间。

        val s = "Hello"

        var sum = 0

               for(i <- 0 util  s.length)  //[0,s.length-1]

    Scala中并没有提供break或continue语句来退出循环。如果需要break语句:

      (1)使用Boolean型的控制变量

       (2)使用嵌套函数——从函数当中return

      (3)使用Breaks对象中的break方法:

        import scala.util.control.Breaks._

        breakable {

          for(…) {

          if(...) break;

          ...

          }

        }

    这里,控制权的转移是通过抛出和捕获异常完成的,因此,如果时间很重要的话,尽量避免使用这套机制。

    8. 高级for循环和for推导式

      (1)可以以 变量 <- 表达式 的形式提供多个生成器,用分号将它们隔开。

        for(i <- 1 to 3; j <- 1 to 3) print ((10 * i + j) + " ") //打印11 12 13 21 22 23 31 32 33

      每个生成器都可以带一个守卫,以 if 开头的Boolean表达式:

        for(i <- 1 to 3; j <- 1 to 3  if  i != j) print((10 * i + j) + " ") //打印12 13 21 23 31 32

      注意if之前并没有分号

      可以使用任意多的定义,引入可以在循环中使用的变量:

        for(i <- 1 to 3; from = 4 - i; j <- from to 3) print((10 * i + j) + " ") //打印 13 22 23 31 32 33

      如果for循环的循环体以yield开始,则该循环会构造一个集合,每次迭代生成集合中的一个值:

        for(1 <- 1 to 10) yield i % 3

        //生成 Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)

    这类循环叫for推导式

    for推到式生成的集合与它的第一个生成器是类型兼容的。

      for(c <- "Hello"; i <- 0 to 1) yield (c + i).toChar  //将生成"HIeflmlmop"

      for(i <- 0 to 1; c <- "Hello") yield (c + i).toChar //将生成Vector('H', 'e', 'l', 'l', 'o', 'I', 'f', 'm', 'm', 'p')

      也可以将生成器、守卫和定义包含在花括号中,并可以一换行的方式而不是分号来分隔它们:

        for{ i <- 1 to 3

          from = 4 - i

          j <- from to 3 }

    9. 函数

      Scala除了方法还支持函数。方法针对对象进行操作,函数不是。不过在Java中我们只能使用静态方法来模拟。

      定义函数,给出函数的名称,参数和函数体,例如:

        def  abs(x : Double) = if (x >= 0) x else -x

        必须给出所有参数的类型只要函数不是递归的,就不用指定返回值类型。Scala编译器可以通过=符号右侧的表达式推断出返回值类型。

      如果函数体需要多个表达式完成,可以用代码块。块中最后一个表达式的值就是函数的返回值。例如:

        def  fac(n : Int) = {

          var r = 1

          for(i <- 1 to n) r = r * i

          r     //返回r的值

        }

      对于递归函数,必须制定返回值类型。例如:

        def fac(n : Int) : Int = if(n<=0) 1 else n * fac(n - 1)

      如果没有返回类型,Scala编译器无法校验n * fac(n - 1)的类型是Int。

    10.默认参数和带名参数

      在调用某些函数时并不显式地给出所有的参数值,对于这些函数可以使用默认参数。例如,

        def  decorate(str : String,  left: String = "[",  right : String = "]") =

          left + str + right

      这个函数的两个参数left和right带有默认值 "[" 和 "]"。调用 decorate("hello")得到"[hello]"。

      如果想对参数的数量,你给出的值不够,默认参数会从后往前逐个应用进来。例如,decorate("hello",">>[")会使用right参数的默认值。

      可以在提供参数值的时候指定参数名,例如:decorate(left=“《《”,str = “hello”,right=“》》”),结果是"《《hello》》"。注意,带名参数并不需要跟参数列表的顺序完全一致。带名参数使得函数更加可读。

      可以混用未命名参数和带名参数,只要那些未命名的参数是排在前面的即可。

        decorate("hello", right = "}>>" //将调用decorate("hello", "[", "}>>")

    11.变长参数

      实现一个可以接受可变长度参数列表的函数会更方便。

        def  sum(args: Int*) = {

          var  result = 0

          for(arg <- args)  result += arg

          result

        }

     可以使用任意多的参数来调用该函数: val s = sum(1, 4, 9 ,16, 25)

     如果已有一个值的序列,则不能将它传入上述函数。例如:val s = sum(1 to 5)  //错误

     如果sum函数被调用传入的是单个参数,那么该参数必须是单个整数,而不是一个整数区间。解决方案:告诉编译器你希望这个参数被当做参数序列处理。追加    :_*

        val s = sum(1 to 5 : _*)  //将1 to 5 当做参数序列处理

  • 相关阅读:
    FCN网络
    YOLO学习
    图像的几何变换-仿射变换和透射变换
    图像处理中的插值方法
    opencv中imgshow图像显示为灰色
    JDBC开发,数据库的连接
    Object类和String类
    动态线条,随鼠标移动吸附效果
    匿名对象,内部类,包,访问修饰符,代码块
    final关键字,static关键字
  • 原文地址:https://www.cnblogs.com/yongwangzhiqian/p/4553053.html
Copyright © 2011-2022 走看看