scala入门2

来源:互联网 发布:js中的延时函数 编辑:程序博客网 时间:2024/06/05 07:16

1. 内建控制结构

Scala内建的控制结构屈指可数,仅有ifwhilefortrymatch和函数调用而已。

1) If

Scalaif语句和其他语言相比没什么不同。它可以检测条件并根据其是否为真,执行两个分支中的一个。

If示例:

val fileName = if(!args.isEmptyargs(0else "default.text"

2) While

Scalawhile循环与其他语言中一直。包括状态判断和循环体,只要状态保持为真,循环体就一遍遍被执行。

While示例:

def gcdLoop(x:Long,y:Long):Long = {

    var a = x;

    var b = y;

    while(a!=0){

      var temp = a

      a =  b % a

      b = temp

    }

    b

  } 

Do-while示例:

  def gcdDoLoop() = {

    var line ="";

    do{

      line = readLine();

      println(line)

    }while(line != "")

  }

Whiledo-while结构之所以被称为循环,而不是表达式,是因为它们不能产生实际有意义的结果。结果的类型是Unit,是表明存在并且唯一存在类型为Unit的值。

3) For

Scalafor表达式是枚举操作的“瑞士军刀”,它可以让你用不同的方式把若干简单的成分组合起来,以表达各式各样的枚举。

枚举集合类

For 能做的最简单的事情就是把集合中的所有元素枚举一遍。

For示例:

  val files = (new java.io.File(".")).listFiles();

  for(file <- files)  //枚举当前目录所有文件

    println(file)

通过使用被称为发生器的语法“file <- files”,遍历files的元素,每一次枚举,名为file的新的val就被元素值初始化。

过滤

当不想枚举集合中的全部元素,而只想过滤出某个子集时,可以通过在for表达式的括号中添加过滤器(filter,if字句,实现。

示例:

val list = List("ABC","BC","QWE","QWAEQW","OPIPUE");

  for(str <- list if(!str.contains("QW"))){

    println(str)

  }

输出结果为:

ABC

BC

OPIPUE

结果中过滤掉包含”QW”字符的字符串。

嵌套枚举

如果加入多个<-字句,就会得到嵌套的循环。

示例:

  val list = List(List("12","56"),List("12","34"),List("34","56"),List("12","34","56"))

  for(

      li <- list 

      if(li.contains("34"));

      l <- li

      if(l.contains("56"))){

      println(li)

  }

输出结果为:

List(34, 56)

List(12, 34, 56)

For表达式中,第一个if语句过滤含“34”字符串的List,有3条匹配,第二个if语句过滤第一个匹配结果中过滤含“56”字符串的List,有2条匹配。

注意:可以使用花括号代替小括号包裹发生器和过滤器。使用花括号的好吃是可以省略使用小括号时必须加的分号。

流间变量绑定

For语句中,当同一个变量需要多次相同计算时,可以通过使用等号(=)把结果绑定到新变量,消除多次重复计算。

示例:

  val list = List("12 34"," 34 56","12 56","12 34 56")

  for(li <-  list 

      if(li.contains("34"));

      temp = li.replace(" """)

      if(temp.startsWith("34"))){

      println(li + ":" + temp)

  }

输出结果为:

 34 56:3456

Temp为绑定的变量,绑定的变量被当作val引入和使用,不过不带关键字val

制造新集合

上述for操作在对枚举值进行操作然后就释放,除此之外,还可以创建一个值去记住每一次的迭代。

示例:

  val list = List(List("12","56"),List("12","34"),List("34","56"),List("12","34","5678"))

  val ma = 

    for{

      li <- list 

      if(li.contains("34"))

      l <- li

      if(l.contains("56"))}

    yield l.length()

println(ma)

输出结果为:

List(2, 4)

返回满足条件字符长度的集合。

4) Try

Scala的异常和其他语言一样,方法除了能以通常的方式返回值以外,还可以通过抛出异常终止执行。

抛出异常

异常的抛出看上去和Java的一模一样,创建一个异常然后同Throw关键字抛出。

示例:

  def half(m:Int){

     val half = ifm % 2 == 0)

       m /2

     else

       throw new RuntimeException("m must be even")

  }

捕获异常

示例:

  try{

    val file = new FileReader("input.txt");

  }catch{

    case ex:FileNotFoundException =>//处理文件未找到异常

    case ex:IOException =>//处理IO异常

  }

选择catch语句的这种语法的原因是和Scala很重要的模式匹配相一致。后续文章中会介绍模式匹配相关内容。

这个try-catch表达式的处理方式和其他语言中异常处理的方式一致。首先是执行程序体,如果抛出异常,则依次尝试每个catch字句。

Finally字句

如果想让某些代码无论方法如何终止都要执行的话,可以将表达式放在finally字句中。

示例:

 val file = new FileReader("input.txt");

  try{

    //处理

  }finally{

    file.close();

  }

finally语句中执行文件流关闭操作。

生成值

和其他大多数scala控制结构一样,try-catch-finally也产生值。

示例:

  val file =

    try {

      new FileReader("input.txt");

    } catch {

      case exFileNotFoundException => //处理文件未找到异常

      case ex: IOException           => //处理IO异常

      new FileReader("default.txt")  

    }

读取“input.txt”文件,如果读取过程中出现异常,则返回默认的“default.txt”文件。

返回的结果情况有以下几种:

① 没有异常抛出,对应于try子句结果

② 抛出异常并被捕获,对应相应的catch子句

③ 抛出异常但是没有被捕获,则没有返回值

注意:finally子句计算得到的值,即使有也会被抛弃,异常finally子句做一些关闭文件之类的清理工作,不应该修改主函数替或catch子句计算的值。

5) 匹配(match)表达式

Scalamatch表达式类似于其他语言的switch语句,它可以提供给你在多个备选项中做选择。

示例:

  val firstArg = if (args.length > 0args(0else ""

  firstArg match {

    case "hello"   => println("scala")

    case "welcome" => println("重庆")

    case "come"    => println("here")

  }

Javaswitch语句比,匹配表达式还有一些重要的差别。其中之一是任何类型的常量,或其他什么东西,都能当成scala里做比较用的样本,而不只是Javacase语句里面的整数类型和枚举常量。另一个区别是在每个备选项的最后并没有break,取而代之的是,break是隐含的,也就是说,不允许从上一个备选项落入到下一个里面去的情况发生。

然而,与Javaswitch相比,最显著的差别或许是match表达式也能产生值。

示例:

 val firstArg = if (args.length > 0args(0else ""

  val arg = firstArg match {

    case "hello"   => "scala"

    case "welcome" => "重庆"

    case "come"    => "here"

  }

6) 不在使用breakcontinue

if替换每一个continue和用布尔变量替换每个break是最简单的方式。布尔变量用来说明while循环是否应该继续。

7) 变量范围

Scala程序所有的变量定义都存在有效作用范围。最常见的情况如,花括号通常引入了新的作用范围,所以任何定义在花括号里的东西超出花括号之后就脱离了范围。

2.函数和闭包

1)方法

定义函数最通用的方法是作为某个对象的成员,这种函数被称为方法(method)。

示例:

class MethodT {

  def add(n: Int, m: Int): Int = {

    pAdd(nm);

  }

  private def pAdd(n: Int, m: Int): Int = {

    n * m + (n + m)

  }

}

AddpAdd函数是定义在MethodT里面的方法。

2)本地函数

将函数定义在别的函数之内,就好像本地变量那样,这种本地函数仅在包含它的代码块中可见,外部无法可见。

示例:

class MethodT {

  def add(n: Int, m: Int): Int = {

    def pAdd(n: Int, m: Int): Int = {

      n * m + (n + m)

    }

    pAdd(n,m)

  }

}

3)头等函数

Scala的函数是头等函数,你不仅可以定义和调用函数,还可以把它们写成匿名的字面量,并把它们作为值传递。

函数字面量被编译进类,并在运行期实例化为函数值,因此函数字面量和值的区别在于函数字面量存在于源代码,而函数值作为对象存在于运行期。

示例:

val increase = (x:Int) =>{

    println("hello")

    println("Scala")

    x+1

  }

increase(10)

函数值是对象,所以如果愿意,可以将其存入变量,它们也是函数,所以你可以使用通常的函数调用写法调用他们。

4)函数字面量的短格式

一是让函数字面量更简短的方式是去除参数类型。

二是某些参数类型是被推断的,省略其外的括号。

示例:

  val list = List(1,2,3,4,5)

  val l = list.filter { x => x > 3 }

示例中第一个x参数省略了参数类型和其外的括号。

5)占位符语法

如果想让函数字面量更简洁,可以把下划线当做一个或更多参数的占位符,只要每个参数在函数字面量内仅出现一次。

示例: 

val list = List(1,2,3,4,5)

val l = list.filter { _> 3 }

_作为占位符,替换短格式中的x参数。

注意:有时把下划线当做参数的占位符,编译器可能无法推断缺失的参数类型,这种情况下,可以使用冒号指定参数类型。

示例:

val f = (_:Int) + (_:Int)

其中多个下划线,表示多个参数。

6)闭包

依照函数字面量在运行时创建的函数值(对象),被称为闭包。名称源自于通过“捕获”自由变量的绑定,从而对函数字面量执行的“关闭”行动。不带自由变量的函数字面量,如(x:Int=> x + 1,被称为封闭项,这里项指的是一小段源代码,因此依照这种函数字面量在运行时创建的函数值严格意思上来讲就不是闭包了,因为(x:Int=> x + 1在编写的时候就已经封闭了。

7)重复参数

Scala中,可以指明函数的最后一个参数是重复的,从而允许客户向函数传入可变长度的参数列表,想要标注一个重复参数,可在参数的类型之后放一个星号。函数内部,重复参数的类型是声明参数类型的数组。

示例:

  def each(s:String*):Unit={

    s.foreach {println}

  }

  each("hello")

  each("hello","scala")

each方法允许输入变长的参数列表。

3. 控制抽象

1) 减少代码重复

所有函数都可以被分成通用部分(每次函数调用中都相同),以及非通用部分(在不同的函数调用中可能会变化)。通用部分是函数体,而非通用部分必须由参数提供。高阶函数(带有其他函数做参数的函数)给了你额外的机会去组织和简化代码。

高阶函数的好处之一是它们能让你创造控制抽象从而减少代码重复。

示例:

  private val files = (new java.io.File(".")).listFiles()

  private def fileMatch(matcher:String => Boolean) = {

    for(file <- files;if matcher(file.getName()))

      yield file

  }

  def endWith(query:String){

    fileMatch { _.endsWith(query)}

  }

  def contains(query:String){

    fileMatch(_.contains(query))

  }

  def matcher(query:String){

    fileMatch(_.matches(query))

  }

2) 减少客户端代码

Scala的标准库提供很多循环方法,用以简化代码,例如exists方法。

示例:

def containsNeg(list:List[Int])=list.exists { _ < 0 } 

通过exists方法,判断集合中元素是否满足判断的表达式。exists控制了抽象,是scala提供的特定用途循环架构,仅需更改判断以满足不同的需求。

3) 柯里化

柯里化的函数被应用与多个参数列表,而不是仅仅一个。

示例:未被柯里化的函数

def sum(x: Int, y: Int) = x + y

实现对两个参数xy的加法。

示例:柯里化的函数

def sum(x:Int)(y:Int) = x + y

柯里化实际上试接连调用两个传统的函数,第一个函数调用带单个名为xInt参数,并返回第二个函数值,第二个函数带Int参数y



0 0
原创粉丝点击