Programming In Scala Reading Note 6

Built-in Control Structures 内置控制结构

1 if 控制结构

scala的if跟java的if结构上相同,功能上也差不太多,scala的说法是,if能够返回一个值

  val fileName = if (!args.isEmpty) args(0) else "default.txt"

这个语句相对普通,但是这里没有引入一个var,而是使用的val。

  println(fileName)  等价于  println(if (!args.isEmpty) args(0) else "default.txt"), 这也是val的一个优势,叫做equational reasoning

2 loop 循环结构

do{...} while(condition)

while(condition) {...}

跟java基本一样,但是这里有一点需要说明的是:赋值语句返回值是Unit,而不是被赋的值,如:

var newLine:String = ""

while ((newLine = readLine()) != "") {...}

如果在java中,readLine()返回值为""的话,那么这个condtion就是不正确的,就要跳出了。

而在scala中,赋值语句的返回值是Unit,它永远不等于"",所以就永远不会terminate了。

因为loop并不返回一个值,所以他不怎么出现在functional language中,作为替代,会使用递归的方式:

def greatestCommonDivisor(a:Int, b:Int):Int =

  if (b==0) a else greatestCommonDivisor(b, b%a)

3 for 结构

遍历集合

for(file <- files){...}

file <- files 称为generator,用来定义一个确定名称的为file的var变量,并且给它赋一系列的值,用以for循环

<- 右侧的表达式为generator expression,用于生成一系列的值

generator expression可以是任何形式的collection

1 to 5 :Range(1, 2, 3, 4, 5)

1 until 5 : Range(1, 2, 3, 4)

过滤集合

只对满足某些条件的集合元素作处理的时候,会用到如:

for(file <- files if file.getName.endsWith(".scala")){...}

多个条件:

for(

  file <- files

  if file.isFile  // 没有(),没有;或,

  if file.getName.endsWith(".scala")

){...}

中间不包含任何的逗号,分号等

I believe this is handsome。。。

嵌套循环

for(

  file <- files

  if file.isFile  // 没有(),没有;或,

  if file.getName.endsWith(".scala");  //注意这个分号!!!

  line <- scala.io.Source.fromFile(file).getLines.toList

  if line.trim.match(".*gcd.*")

){...}

for body里面可以包含当前的file信息和当前line信息。。。

如果想要去掉这个;的话,我们可以把for后面的小括号换成大括号

for{

  file <- files

  if file.isFile  // 没有(),没有;或,

  if file.getName.endsWith(".scala")  // 这里不再有分号,因为我们用的是大括号{}

  line <- scala.io.Source.fromFile(file).getLines.toList

  if line.trim.match(".*gcd.*")

}{...}

循环中绑定变量

for(

  file <- files

  if file.isFile  // 没有(),没有;或,

  if file.getName.endsWith(".scala");

  line <- scala.io.Source.fromFile(file).getLines.toList

  trimmed = line.trim

  if trimmed.match(".*gcd.*")

){...}

引入的这个trimmed是一个val,后续的代码中可以使用它。

for循环生成一个新的集合变量

for clauses yield body

首先这个yield的位置需要注意,在for条件的后面,for body的前面,

for{condition...} yield { for body}

这个for语句是能够返回一个对象的集合的

4 try

Exception,发生一个Exception的时候,会被无情地抛出,然后这个异常会按照方法调用栈的调用顺序往回返,直到有一个方法处理了这个Exception,不然就一直回溯到最后一个方法,然后抛给编译器。

throw表达式

throw new IllegalArgumentException,这样就产生了一个错误参数的异常,也就是说throw语句是有返回值的。

val half =
  if (n % 2 == 0)
    n / 2
  else
    throw new RuntimeException("n must be even")

上面的代码中,如果传递进来的n不是偶数的话,就会抛出一个运行时异常,这个异常会被处理,而造成half没有值,没有被初始化。所以任何想要使用这个half的程序都不会有什么问题。

catch表达式

catch语句被用来跟scala中的一个很重要的概念:模式匹配(pattern matching)来保持一致。

try {
  val f = new FileReader("input.txt")
  // Use and close file
} catch {
  case ex: FileNotFoundException => // Handle missing file
  case ex: IOException => // Handle other I/O error
}

catch中的每一个case代表一种情况,编译器会检查其类型是否为指定的类型,如果是的话,执行后面的语句,如果不是继续直到找到对应的异常类型,如果都不满足的情况下,会终止这个catch语句,抛异常给方法的调用者。

finally表达式

基本上是为副作用而设置的一个表达式。

The result is that of the try clause if no exception is thrown, or the relevant catch clause if an exception is thrown and caught.

If an exception is thrown but not caught, the expression has no result at all.

The value computed in the finally clause, if there is one, is dropped.

try-catch-finally表达式的值:

如果没有异常抛出,那么其值就是try表达式的值。

如果有异常抛出,且被catch捕获了,那么就是这个捕获异常语句的值。

如果异常抛出,且没有被捕获住,那么这个表达式就没有值。而不是finally的值。

尽管finally语句中包含表达式返回值,其值也会被丢弃掉。

不得不说这很残酷,很难理解。scala提供的解释是,finally语句的用途就是为了:

1 关闭一个文件

2 关闭一个套接字

3 关闭数据库连接等等

def some = try {return 1} finally {return 2}的返回值确实是2,但是这并不是scala推荐的做法。

def some = try { 1 } finally { 2 }的返回值是2,这才是scala推荐的形式。。。

The best way to think of finally clauses is as a way to ensure some side effect happens, such as closing an open file.

finally就是为了副作用而生的。

5 match表达式

_, 通配符wildcard,用来充当一个不能确定值的选项。

match的适用对象要比java的switch要多,java仅仅适用于Integer类型的或者Enum类型的,scala的match能够适应任意常量。

sth4match match {

  case some1 => //do something for some1

  case some2 => //do something for some2

  case _ => // do something for other condition

}

另外match语句的case中没有break,这个break是默认追加进来的,在每一个alternative后面。

最后一个最重要的区别应该是每一个case都会有一个返回值。最好不要仅仅让每一个case产生副作用。

6 不用beak和continue

替换break和continue的方式就是尝试用递归来实现需求,假如遍历数组元素,找到第一个不以-开头的,且以.scala结尾的元素

def searchFrom(index:Int, args:Array[String]):Int =

  if (index >= args.length) return -1  // 提供的index有问题

  else if (args(index).startsWith("-")) searchFrom(index+1, args)  // 发现有毛病,继续下一个,也就是实现了continue

                                    // 注意他出现的次序,应该把该排除掉的情况放到正确的情况前面,以及时过滤掉

  else if (args(index).endsWith(".scala")) index  // 值发现了,返回给这个方法的调用者,break的功能实现了

  else searchFrom(index+1, args)  // 如果尚未发现,就继续下一个,这个语句一定要放到最后执行,也就是while循环还要继续

        // 递归方法必须指定返回值,不然方法体中调用方法产生的返回值编译器根本就无从得知。

  

7 variable scope 变量的作用域

跟java基本相同,不过java中如果声明了一个变量a,那么这个a就不能够再被随便声明了。

而Scala中,在一个括号里面就可以定义任意一个名称的变量了,不管是否存在,但是需要在大括号的外面追加一个分号。。。不知道什么意思。。。

8 重构指令式编码

指令式编码的一个显著特点就是var的引入和副作用的产生。

将var去除掉,只引入必要的val。

不要副作用,而只是把需要的信息提供给方法的调用者。

函数式编程的一个显著特点就是,方法特别多,但是方法功能又非常具体。

举一个书上的例子说明:

打印一个1到10的乘法表格,java的方式就是双重for循环。

scala也同样是双重for循环,只不过分配到了两个方法中,详细说一下:

1 1 to 10 行

2 1 to 10 列

3 保证格式不错乱

def makeMultiTable() = {

  // 一共十行数据,把每行数据的获取交给makeRow方法

  val tableSeq = for (row <- 1 to 10) yield makeRow(row)

  // 把获得的seq整理一下

  tableSeq.mkString("\n")

}

// 每一行数据是由每一列数据组成的,交给makeRowSeq去处理

def makeRow(rowIndex:Int) = makeRowSeq(rowIndex).mkString

// 对每一个点进行处理,获得对应的行的数据,Vector

def makeRowSeq(rowIndex:Int) =

  for(col <- 1 to 10)

  yield

  {

    val point = (row * col).toString

    val gap = " " * (4 - point.length)

    // RETURN ELEMENT

    gap + point

  }

Programming In Scala Reading Note 6

时间: 2024-10-13 22:08:36

Programming In Scala Reading Note 6的相关文章

Programming In Scala Reading Note 3

Class and Object class TestClass { val some = 1 } 生成的class文件中会包含一个some()方法,并且这个方法是public的,也就是说类外可以通过类的对象来获取这个some的值 修改: class TestClass { private val some = 1 } 会生成一个private的some()方法,返回值也是some.但是现在类外是访问不到的 类的方法的参数默认是val类型的 副作用大部分用来修改一个属性的值或者开关一个I/O,只

Programming In Scala Reading Note 7

函数和闭包 1 成员方法 java中函数存在的方式,我们给一个类追加一个功能的途径就是给他追加一个方法. 2 本地方法 所谓的本地方法就是存在于一个方法内部的方法. 如果一个类中有一个方法是private的,且只有一个方法使用到他,那么这个方法完全可以被定义为一个本地方法 3 函数式一等公民 方法分为: 1 方法名称 def add 2 方法参数 (a:Int, b:Int) 3 赋值符号 = 4 方法体 a + b 其实,(a:Int, b:Int) => a + b,就构成了一个基本的函数了

Programming In Scala Reading Note 1

Chapter1 and Chapter2 方法定义: def methodName(param1: ParamType, param2: ParamType2, [maybe more]): ReturnType = { // method body } 函数式编程中一个约定俗成的说法就是,方法会返回一个值,不然一个方法的存在就是在产生副作用,而避免副作用是函数式编程的一个初衷. 数组的访问: scala中的数组是Array[ContentType],声明一个数组的时候需要指定数组的大小和所包

Programming In Scala Reading Note 8

AJAX XMLHttpRequest,是AJAX得以实现的基础 他是一个对象,有几个需要记住的方法和属性: XMLHttpRequest方法 open(method, url, async, username, password) method: post或get url: 请求地址 async: boolean,默认为ture,是否异步? 后面的基本上没啥意思... send(content) xmlHttpRequest调用了open方法之后,并没有真正发生一个请求事件. send执行的时

Programming In Scala Reading Note 4

Basic Types and Operations Something new according to Java 1 + 2 跟 (1).+(2) 是一样的. val str = "Hello world" str indexOf 'o' 跟 str.indexOf('o')是一样的 indexOf有两种形式的参数,int和str,其中这个int就是用来确定是否存在一个char的.... Any method can be an operator 这句话应该这么理解,str.ind

Programming In Scala Reading Note 2

Learn to programming in funtional way 如果一个方法中存在var的话,那么这个方法很可能就是指令式编程. 如果一个方法中只存在val的话,那么这个方法很可能是函数式编程. 我们需要尝试着把方法中的val删除掉. 副作用,一个方法满足函数式编程的基本要求,但是返回值是一个Unit的话,那么可以肯定这个方法是有副作用的. 而我们应该避免让一个方法有副作用. 不产生副作用就不会对我们有意义,于是我们需要最小化副作用,让每一个方法都干一件事儿,返回给我们一个值. Pr

Programming In Scala Reading Note 5

Functional Object Advantages and Disadvantages of Immutable Object Adv 1. 不可变对象更具容易被推断出来,因为它不会随着时间的变化而造成值的变化. Adv 2. 不可变对象可以自动地传递不会发生变化,而传递可变对象的话,需要首先对可变对象进行备份,以防止在其它过程中对对象的状态造成了修改. Adv 3. 线程不能够更改(corrupt:腐化,堕落)不可变对象的状态,注定他是线程安全的. Adv 4. 不可变对象拥有安全的Ha

thinking in java ----reading note (1)

# thinking in java 4th# reading note# victor# 2016.02.10 chapter 1 对象入门 1.1 抽象的进步    (1) 所有东西都是对象.    (2) 程序是一大堆对象的组合,对象间通过消息联系.    (3) 通过封装现有对象,可制作出新型对象.    (4) 每个对象都有一种类型(某个类的实例).    (5) 同一类的所有对象都能接受相同的消息.    1.2 对象的接口 & 1.3 实现方法的隐藏     接口规定了可对一个特定

jQueryInAction Reading Note 7.

jQuery插件命名规则 jquery.pluginName.js pluginName指代的是插件的名称,如voctrals,tlaliu或者更有意义的名称. 简化jQuery函数的参数列表 如果有一个函数有多个参数,但是并不是每一个参数都是必须的,可以把必须的参数放到前面,不必须的参数包装成一个object. 如: function complex(param, options){ var settings = $.extend( { option1 : defaultValue1, opt