scala编程(七)——内建控制结构
几乎所有的 Scala 的控制结构都会产生某个值。这是函数式语言所采用的方式,程序被看成是计算值的活动,因此程序的控件也应当这么做。另外,指令式语言经常具有三元操作符(如 C,C++和 Java 的?:操作符),表现得就像 if,却产生值。Scala 采用了这种三元操作符模型,但是把它称为 if。 换句话说,Scala 的 if 可以产生值。于是 Scala 持续了这种趋势让 for,try 和 match 也产生值。
if 表达式
Scala 的 if 如同许多其它语言中的一样工作。它测试一个状态并据其是否为真,执行两个分支中 的一个,并能返回分支中的值。
def main(args: Array[String]): Unit = {
    val filename =
      if (!args.isEmpty) args(0)
      else "default.txt"
    println(filename)
  }
if 有了两个分支:如果 args 不为空,那么初始化元素,args(0),被选中。否则,缺省 值被选中。这个 if 表达式产生了被选中的值,然后 filename 变量被初始化为这个值。这段代码更短一点儿,不过它的实际优点在于使用了 val 而不是 var。使用 val 是函数式的风格,并能以 差不多与 Java 的 final 变量同样的方式帮到你。它让代码的读者确信这个变量将永不改变,节省了他们扫描变量字段的所有代码以检查它是否改变的工作。
使用 val 而不是 var 的第二点好处是他能更好地支持等效推论:equational reasoning。在表达式没有副作用的前提下,引入的变量等效于计算它的表达式。因此,无论何时都可以用表达式替代变量名。如,要替代 println(filename),你可以这么写: println(if (!args.isEmpty) args(0) else "default.txt") 选择权在你。怎么写都行。使用 val 可以帮你安全地执行这类重构以不断革新你的代码。
尽可能寻找使用 val 的机会。它们能让你的代码既容易阅读又容易重构。
while 循环
while 和 do-while 结构被称为“循环”,不是表达式,因为它们不产生有意义的结果,结果的类 型是 Unit。说明产生的值(并且实际上是唯一的值)的类型为 Unit。被称为 unit value,写做 ()。 ()的存在是 Scala 的 Unit 不同于 Java 的 void 的地方。
  def main(args: Array[String]): Unit = {
    def greet() = println("hello")
    println(greet() == ())
  }
打印结果为:
hello
true
由于方法体之前没有等号,greet 被定义为结果类型为 Unit 的过程。因此,greet 返回 unit 值()。这被下一行确证:比较 greet 的结果和 unit 值()的相等性,产生 true。
另一个产生 unit 值的与此相关的架构,是对 var 的再赋值,它将返回()类型。
def main(args: Array[String]): Unit = {
    var content = ""
   println((content = StdIn.readLine()) == ())
   println((content = StdIn.readLine()) == ())
  }
这里的readLine函数并不会像Java那样返回从控制台读取到的内容,而是始终返回()即unit类型。
第一次输入hello,第二次输入一个空字符串,两次结果均为true;
for 表达式
Scala 的 for 表达式是为枚举准备的“瑞士军刀”。它可以让你用不同的方式把若干简单的成分组合来表达各种各样的枚举。简单的用法 完成如把整数序列枚举一遍那样通常的任务。更高级的表达式可以列举不同类型的多个集合,可以用任意条件过滤元素,还可以制造新的集合。
1)枚举集合类
def main(args: Array[String]): Unit = {
    val array = Array(1,2,3,4,5)
    for(elem <- array)
      println(elem)
  }
打印如下:
1
2
3
4
5
这样做,你的代码变 得更短并规避了许多枚举数组时频繁出现的超位溢出:off-by-one error。该从 0 开始还是从 1 开 始?应该加-1,+1,还是什么都不用直到最后一个索引?这些问题很容易回答,但也很容易答错。 还是避免碰到为佳。
2)过滤
有些时候你不想枚举一个集合类的全部元素。而是想过滤出一个子集。你可以通过把过滤器:filter: 一个 if 子句加到 for 的括号里做到。如果愿意的话,你可以包含更多的过滤器。只要不断加到子句里即可。如果在发生器中加入超过一个过滤器,if 子句必须用分号分隔。
  def main(args: Array[String]): Unit = {
    val array = Array(1,2,3,4,5,6,7,8,9,10)
    for(elem <- array if(elem>5);if(elem%2 == 0))
      println(elem)
  }
打印结果为:
6
8
10
3)制造新集合
你还可以创建一个值去 记住每一次的迭代。只要在 for 表达式之前加上关键字 yield。格式如下:
for(表达式) yield {表达式};最后返回yield表式的结果。
当 for 表达式完成的时候,结果将是一个包含了所有产生的值的集合。结果集合的类型基于枚举子句处理的集合类型。
示例如下:
def main(args: Array[String]): Unit = {
    val array = Array(1,2,3,4,5,6,7,8,9,10)
    val  elems: Array[String] =
      for(elem <- array if(elem>5);if(elem%2 == 0))
      yield elem.toString
    elems.foreach(println)
  }
打印结果:
6
8
10
使用 try 表达式处理异常
Scala 的异常和许多其它语言的一样。代之用普通方式那样返回一个值,方法可以通过抛出一个异常中止。方法的调用者要么可以捕获并处理这个异常,或者也可以简单地中止掉,并把异常升级到调用者的调用者。异常可以就这么升级,一层层释放调用堆栈,直到某个方法处理了它或没有剩下其它的方法。
1)抛出异常
异常的抛出看上去与 Java 的一模一样。首先创建一个异常对象然后用 throw 关键字抛出:
throw new IllegalArgumentException
Scala 里, throw 也是有结果类型的表达式
def main(args: Array[String]): Unit = {
    val n = 1;
    val half =
      if (n % 2 == 0)
        n / 2
      else
        throw new RuntimeException("n must be even")
    println("hello"+half)
  }
这里发生的事情是,如果 n 是偶数,half 将被初始化为 n 的一半。如果 n 不是偶数,那么在 half 能被初始化为任何值之前异常将被抛出。因此,无论怎么说,把抛出的异常当作任何类型的值都 是安全的。任何使用从 throw 返回值的尝试都不会起作用,因此这样做无害。
从技术角度上来说,抛出异常的类型是 Nothing。尽管 throw 不实际得出任何值,你还是可以把 它当作表达式。这种小技巧或许看上去很怪异,但像在上面这样的例子里却常常很有用。if 的一 个分支计算值,另一个抛出异常并得出 Nothing。整个 if 表达式的类型就是那个实际计算值的分支的类型。
打印结果如下:
Exception in thread "main" java.lang.RuntimeException: n must be even
这同时
说明:当异常未被捕获时,异常之后的代码不会被执行;
2)捕获异常
try-catch 表达式的行为与其它语言中的异常处理一致。程序体被执行,如果抛出异常,每个 catch 子句依次被尝试。本例中,如果异常是 FileNotFoundException,那么第一个子句将被执行。如果是IOException 类型,第二个子句将被执行。如果都不是,那么 try-catch 将终结并把异常上升出去。
def main(args: Array[String]): Unit = {
    try {
      val f = new FileReader("input.txt")
      // Use and close file
    } catch {
      case ex: FileNotFoundException => println("file not found ")// Handle missing file
      case ex: IOException => println("io error")// Handle other I/O error
    }
  }
}
打印结果如下:
file not found
与 Java 的一个差别是 Scala 里不需要你捕获检查异常:checked exception,或把它们声明在 throws 子句中
如果想让某些代码无论方法如何中止都要执行的话,可以把表达式放在 finally 子句里。如,你 或许想让打开的文件即使是方法抛出异常退出也要确保被关闭。
和其它大多数 Scala 控制结构一样,try-catch-finally 也产生值。如,代码展示了如何尝试拆分 URL,但如果 URL 格式错误就使用缺省值。结果是,如果没有异常抛出,则对应于 try 子句;如果抛出异常并被捕获,则对应于相应的 catch 子句。如果异常被抛出但没被捕获,表达式就没有返回值。由 finally 子句计算得到的值,如果有的话,被抛弃。通常 finally 子句做一 些清理类型的工作如关闭文件;他们不应该改变在主函数体或 try 的 catch 子句中计算的值。
object Demo8 {
  def urlFor(path: String) = {
    try {
      new URL(path)
    } catch {
      case e: MalformedURLException =>
        new URL("http://www.scalalang.org")
    }
  }
  def main(args: Array[String]): Unit = {
    val s = "abc";
    val url = urlFor(s)
    println(url)
  }
}
打印结果为:
http://www.scalalang.org
match 表达式
Scala 的匹配表达式允许你在许多可选项:alternative 中做选择,就好象其它语言中的 switch 语句。通常说来 match 表达式可以让你使用任意的模式:pattern 做选择。
 def main(args: Array[String]): Unit = {
    val firstArg = "salt"
    firstArg match {
      case "salt" => println("pepper")
      case "chips" => println("salsa")
      case "eggs" => println("bacon")
      case _ => println("huh?")
    }
  }
打印结果为:
pepper
与 Java 的 switch 语句比,匹配表达式还有一些重要的差别。其中之一是任何种类的常量,或其 他什么东西,都能用作 Scala 里的 case,而不只是 Java 的 case 语句里面的整数类型和枚举常量。 在这个例子里,可选项是字串。另一个区别是在每个可选项的最后并没有 break。取而代之,break 是隐含的,不会有从一个可选项转到另一个里面去的情况。这通常把代码变短了,并且避免了一 些错误的根源,因为程序员不再因为疏忽在选项里转来转去。
与 Java 的 switch 相比最显著的差别,或许是 match 表达式也能产生值。
 def main(args: Array[String]): Unit = {
    val firstArg = "salt"
    val friend =
      firstArg match {
        case "salt" => "pepper"
        case "chips" => "salsa"
        case "eggs" => "bacon"
        case _ => "huh?"
      }
    println(friend)
  }
打印结果为
pepper
scala编程(七)——内建控制结构的更多相关文章
- Scala学习笔记——内建控制结构
		Scala的内建控制结构包括:if.while.for.try.match和函数调用 1.if表达式 //常见的写法 var filename = "name" if (!args ... 
- Scala的内建控制结构
		Scala中的内建控制机构仅有if.while.for.try.match和函数调用.虽然Scala的基础控制结构少,但也足以支持指令式语言里所有的实质内容.因为它们都能产生值,有助于缩短代码. 程序 ... 
- Scala 编程(四)内建控制结构
		if 表达式 Scala 的 if 如同许多其它语言中的一样工作.它测试一个状态并据其是否为真,执行两个分支中的一个: var filename = "default.txt" i ... 
- Scala 基础(6)—— 控制结构
		1. Scala 的内建控制结构 Scala 有几个内建的控制结构,包括: if 表达式 while 循环和 do-while 循环 for 表达式 try 表达式 match 表达式 Scala 的 ... 
- scala-- 内建控制结构
		内建控制结构  scala 内建的控制结构很少,只有 if while for try match 和函数调用 几种. 因为scala 从语法层面支持函数字面量.几乎所有的scala控制结构都会产生 ... 
- OpenGL ES着色器语言之语句和结构体(官方文档第六章)内建变量(官方文档第七、八章)
		OpenGL ES着色器语言之语句和结构体(官方文档第六章) OpenGL ES着色器语言的程序块基本构成如下: 语句和声明 函数定义 选择(if-else) 迭代(for, while, do-wh ... 
- Scala学习笔记(五):内建控制循环
		前言 Scala中内建控制循环包括if.while.for.try.match和函数调用. if和while与java类似,不做介绍. for 基础用法 def main(args: Array[St ... 
- Unity3d 网络编程(一)(Unity3d内建网络Network介绍)
		首先个人说说题外话,Unity3d使用的网络库核心是用C++实现的一款商业网络游戏引擎库. RakNet.所以对于移动设备来说,用Unity3d来写server是全然能够的,而且内建网络库的各项功能封 ... 
- python高级编程之(类级):子类内建类型
		# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #类级 #在2.2中,提出了类型(type0与类(class)统一( ... 
随机推荐
- 关于Oracle中job定时器(通过create_job创建的)配置示例
			begin dbms_scheduler.create_job(job_name => 'JOB_BASIC_STATISTIC', job_type => 'STORED_PROCEDU ... 
- postman批量接口测试注意事项
			1.使用cvs文件 导入文件后最后行出现\r符号 用文本打开 删除最后一行空白行 2.打印cvs文件中的接口调用的参数 Pre-request Script: var beginDate=data.b ... 
- OpenMP笔记(三)
			个人博客地址:http://www.bearoom.xyz/2019/02/21/openmp3/ 这一部分主要记录一些指令的使用. 一.parallel的使用 parallel是用于构造并行块的,也 ... 
- 4. react 基础 - 编写 todoList 功能
			编写 TodoList 功能 react 入口 js #src/index.js import React from 'react'; import ReactDOM from 'react-dom' ... 
- LINUX之ntp时间同步服务配置
			本篇将介绍LINUX之ntp服务配置,时钟同步服务器配置.这个在很多地方都会用到,保持各主机之前的时间保持一致,保证主机之间的心跳稳定. 三台主机都是centos7 192.168.1.110 mas ... 
- JSP页面中提示JSTL标签无法找到的错误
			无法解析标签库的错误 1.应该是项目中少了jstl.jar和 standard.jar这两个jar包. 下载地址:https://www.onlinedown.net/soft/1162736.htm ... 
- python3 文件流
			文件流 # python里的打开一个文件用open(),如果不能打开,会抛出异常:OSError # 文件流的基本参数 # . file: 打开一个文件 # . mode: 打开的模式,默认模式为tx ... 
- 数据分析-Numpy-Pandas
			补充上一篇未完待续的Numpy知识点 索引和切片 数组和标量(数字)之间运算 li1 = [ [1,2,3], [4,5,6] ] a = np.array(li1) a * 2 运行结果: arra ... 
- 洛谷 P2278 [HNOI2003]操作系统
			题目传送门 解题思路: 一道没啥思维含量的模拟题,但是个人感觉代码实现不简单,可能是我太弱了,花了我6个小时,3次重写. AC代码: #include<iostream> #include ... 
- C++类的访问控制关键字
			public:修饰的成员变量和函数,可以在类的内部和类的外部被访问. private:修饰的成员变量和函数,只能在类的内部被访问,不能在类的外部被访问. protected:修饰的成员变量和函数,只能 ... 
