Scala语法扩充

一、Scala函数闭包

二、Scala正则表达式

三、Scala异常处理

四、Scala迭代器

五、Scala Collection(集合)

一、Scala函数闭包

函数闭包:

  • 我们介绍的函数都只引用到传入的参数,假如我们定义入如下的函数:

  • (x:Int)=> x + more

  • 这里我们引入一个自由变量more。它不是所定义的函数的参数,而这个变量定义在函数的外面,比如:

  • var more = 1

那么我们有如下的结果:


scala> var more = 1
more: Int = 1

scala> val addMore = (x:Int) => x + more
addMore: Int => Int = <function1>

scala> addMore(100)
res33: Int = 101
  • 这样定义的函数变量addMore成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。

  • 有意思的是:当这个自由变量发生变化时,Scala的闭包能够捕获到这个变化,所以Scala的闭包捕获的是变量本身而不是变量的值。

scala> more = 9999
more: Int = 9999

scala> addMore(100)
res34: Int = 10099

同样的,如果变量在闭包内发生变化,也会反映到函数外面定义的闭包的值,比如


scala> val someNumbers = List(-11,-10,5,0,5,10)
someNumbers: List[Int] = List(-11, -10, 5, 0, 5, 10)

scala> var sum = 0
sum: Int = 0

scala> someNumbers.foreach(sum += _)

scala> sum
res38: Int = -1
  • 我们可以看到在闭包中修改sum的值,其结果还是传递到闭包的外面。

  • 如果一个闭包所访问到的变量有几个不同的版本,比如一个闭包使用了一个函数的局部变量(参数),然后这个函数调用很多次,那么所定义的闭包应该使用所引用的局部变量的哪个版本呢?简单的说,该闭包定义所引用的变量为定义该闭包是变量的值,也就是定义闭包是相当于保存了当时程序状态的一个快照。比如我们定义下面一个函数闭包:


scala> def makeIncreaser(more:Int) = (x:Int) => x + more
makeIncreaser: (more: Int)Int => Int

scala> val inc1=makeIncreaser(1)
inc1: Int => Int = <function1>

scala> val inc9999=makeIncreaser(9999)
inc9999: Int => Int = <function1>

scala> inc1(10)
res39: Int = 11

scala> inc9999(10)
res40: Int = 10009
  • 当我们调用makeIncreaser(1)时,创建了一个闭包,该闭包定义时more的值为1,而调用makeIncreaser(9999)所创建的闭包的more的值为9999。此后你也无法修改已经返回的闭包的more的值。因此inc1始终为加1,而inc9999始终为加9999。

二、Scala正则表达式

  • Scala通过scala.util.matching包中的Regex类来支持正则表达式。以下实例演示了使用正则表达式查找单词Scala
import scala.util.matching.Regex

object Test{
	def main(args: Array[String]) {
			val pattern = "Scala".r
			val str = "Scala is Scalable and cool"

			println(patern findFirstIn str)

}
}
  • 执行以上代码:
  • 输出结果:Some(Scala)

实例中使用String类的r()方法构造了一个Regex对象。
然后使用findFirstIn方法找到首个匹配项。
如果需要查看所有的匹配项可以使用findAllIn方法。
你可以使用mkString()方法来连接正则表达式匹配结果的字符串,并可以使用管道(|)来设置不同的模式:

import scala.util.matching.Regex

object ChangeLongApp {
  def main(args: Array[String]) {
      val pattern = new Regex("(S|s)cala")      //首字母可以是大写S或小写s
      val str = "Scala is scalable and cool"

      println((pattern findAllIn str).mkString(","))      //使用逗号,连接返回结果
  }

}

输出:Scala,scala

如果需要将匹配的文本替换为指定的关键字,可以使用replaceFirstIn()方法来替换第一个匹配项,使用replaceAllIn()方法来替换所有匹配项,实例如下:

import scala.util.matching.Regex

object ChangeLongApp{
		def main(args: Array[String]) {
				val pattern = "(S|s)cala".r
				val str = "Scala is scalable and cool"

				println(pattern replaceFirstIn(str,"java"))
	}
}
  • 输出结果如下:java is scalable and cool

正则表达式:

Scala的正则表达式继承了Java的语法规则,Java则大部分使用了Perl语言的规则。

下表我们给出了常用的一些正则表达式规则:

表达式匹配规则
^匹配输入字符串开始的位置
$匹配输入字符串结尾的位置
.匹配除"\r\n"之外的任何单个字符
[…]字符集。匹配包含的任一字符。例如,"[abc]“匹配"plain"中的"a”.
[^…]反向字符集。匹配未包含的任何字符。例如,"[^abc]“匹配"plain"中"p”,“l”,“i”,“n”.
\A匹配输入字符串开始的位置(无多行支持)
\z字符串结尾(类似$,但不受处理多行选项的影响)
\Z字符串结尾或行尾(不受处理多行选项的影响)
re*重复零次或更多次
re+重复一次或更多次
re?重复零次或一次
re{ n }重复n次
re{ n, }-
re{ n,m }重复n到m次
ab
(re)匹配 re,并捕获文本到自动命名的组里
(?: re)匹配re,不捕获匹配的文本,也不给此分支分配组号
?> re贪婪子表达式
\w匹配字母或数字或下划线或汉字
\\w匹配任意不是字母,数字,下划线,汉字的字符
\s匹配任意的空白符,相当于[\t\n\r\f]
\S匹配任意不是空白字符的字符
\d匹配数字,类似[0-9]
\D匹配任意非数字的字符
\G当前搜索的开头
\n换行符
\b通常是单词分界位置,但如果在字符类里使用代表退格
\B匹配不是单词开头或结束的位置
\t制表符
\Q开始引号:\Q(a+b)*3\E 可匹配文本"(a+b)*3"
\E结束引号:\Q(a+b)*3\E 可匹配文本"(a+b)*3"

正则表达式实例:

实例描述
.匹配除"\r\n"之外的任何单个字符
[Rr]uby匹配"Ruby"或"ruby"
rub[ye]匹配"ruby"或"rube"
[aeiou]匹配小写字母:aeiou
[0-9]匹配任何数字,类似[0123456789]
[a-z]匹配任何ASCII小写字母
[A-Z]匹配任何ASCII大写字母
[a-zA-Z0-9]匹配数字,大写字母
[^aeiou]匹配除了aeiou以外的其它字符
[^0-9]匹配除了数字的其它字符
\d匹配数字,类似:[0-9]
\D匹配非数字,类似:[^0-9]
\s匹配空格,类似:[\t\r\n\f]
\S匹配非空格,类似[^\t\r\n\f]
\w匹配字母,数字,下划线,类似:[A-Za-z0-9_]
\W匹配非字母,数字,下划线:类似:[^A-Za-z0-9]
ruby?匹配"rub"或"ruby":y是可选的
ruby*匹配"rub"加上0个或多个的y
ruby+匹配"rub"加上一个或多个的y
\d{3}刚好匹配3个数字
\d{3,}匹配3个或多个数字
\d{3,5}匹配3个、4个或5个数字
\D\d+无分组:+重复\d
(\D\d)+/分组:+重复\D\d对
([Rr]uby(,)?)+匹配"Ruby"、“Ruby,ruby,ruby”,等等

注意上表中的每个字符使用了两个反斜线。这是因为住在Java和Scala中字符串中的反斜线是转义字符。所以如果你要输出\,你需要在字符串中写成.\.来获取一个反斜线。查看以下实例:

import scala.util.matching.Regex

object ChangeLongApp {
  def main(args: Array[String]) {
      val pattern = new Regex("abl[ae]\\d+")
      val str = "ablaw is able1 and cool"

    println((pattern findAllIn str).mkString(","))

  }
}

输出:able1

三、Scala异常处理

  • Scala的异常处理和其它语言比如Java类似。
  • Scala的方法可以通过抛出异常的方法的方式来终止相关代码的运行,不必通过返回值。

抛出异常:

  • Scala抛出异常的方法和Java一样,使用throw方法,例如,抛出一个新的参数异常:
throw new IllegalArgumentException

捕获异常

  • 异常捕捉的机制与其他语言中一样,如果有异常发生,catch字句是按次序捕捉的。因此,在catch字句中,越具体的异常越要靠前,越普遍的异常越要靠后。如果抛出的异常不在catch字句中,则异常无法被处理,会被升级到调用者处。

  • 捕捉异常的catch子句,语法和其他语言中不太一样。在Scala中,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列的case字句,如下列所示:

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException

object Test {
		def main(args: Array[String]) {
				try {
						val f = new FileReader("input.txt")
					}catch {
				case ex: FileNotFoundException => {
					println("Missing file exception")
				}
				case ex: IOException  => {
					println("IO Exception")
				}
			}
	}
}

执行以上代码,输出结果为:

  • Missing file exception

更换路径:

  • val f = new FileReader(“C:/Users/Administrator/Desktop/testInfo1.txt”)
  • 输出打印:无异常信息

小结:

  • catch 字句里的内容跟match里的case是完全一样的。由于异常捕捉是按次序,如果是最普遍的异常,Throwable,写在最前面,则在它后面的case都捕捉不到,因此需要将它写在最后面。

finally语句

  • finally语句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,实例如下:
import java.io.{FileNotFoundException, FileReader, IOException}

object Text {
		def main(args: Array[String]) {
			try {
			val f = new FileReader("input.txt")
		} catch {
				case ex: FileNotFoundException => {
				println("Missing file exception")
		}
			case ex: IOException => {
				println("IOException")
			}
		}finally {
			println("Exiting finally.......")
		}
	}
}

输出结果:
Missing file exception
Exiting finally.......

2、更换读入文件路径:
val f = new FileReader("C:/Users/Administrator/Desktop/testInfo.txt")
输出结果:
Exiting finally.......

由上面的测试说明:finally语句用于执行不管是正常处理还是有异常发生时都需要执行的步骤。

四、Scala Iterator(迭代器)

Scala Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法。
迭代器it的两个基本操作是next和hasNext。
调用it.next()会返回迭代器的下一个元素,并且更新迭代器的状态。
调用it.hasNext()用于检测集合中是否还有元素。
让迭代器it逐个返回所有元素最简单的方法就是使用while循环。

def main(args: Array[String]) {
	val it = Iterator("百度","京东","饿了么","美团","小米","腾讯","阿里")		
	
	while (it.hasNext){
		println(it.next())
	}
}

输出结果:
百度
京东
饿了么
美团
小米
腾讯
阿里

查找最大与最小元素:

  • 你可以使用it.min和it.max方法从迭代器中查找最大与最小元素,实例如下:
object IteratorApp {
  def main(args: Array[String]): Unit = {
      val ita = Iterator(20,40,2,57,98)
      val itb = Iterator(20,40,50,2,69,90)

      println("最大元素是:" + ita.max)
      println("最小元素是:" + itb.min)

    }
}
输出结果:
最大元素是:98
最小元素是:2

获取迭代器长度:

object IteratorApp{
  def main(args: Array[String]): Unit = {
      val ita = Iterator(20,30,2,50,70,90)

      val itb = Iterator(25,35,2,40,60)

    println("ita.size的值:"  + ita.size)
    println("itb.size的值:"  + itb.size)
  }

输出结果:
ita.size的值:6
itb.size的值:5

Scala Iterator常用方法:

方法描述
def hasNext:Boolean如果还有可返回的元素,返回true
def next():A返回迭代器的下一个元素,并且更新迭代器的状态
def ++(that: => Iterator[A]):Iterator[A]合并两个迭代器
def ++[B >:A](that :=> GenTraversableOnce[B]):Iterator[B]合并两个迭代器
def addString(b: StringBuilder, sep: String): StringBuilder添加一个字符串到 StringBuilder b,并指定分隔符

https://www.runoob.com/scala/scala-iterators.html

迭代器addString举例:

  • 一脸懵逼不知道方法怎么用怎么办呢?
  • 直接定位到源码,ita.addString,Ctrl + 鼠标左键,

在源码中有完整的定义和例子说明,应该传入几个参数。

 /** Appends all elements of this $coll to a string builder using start, end, and separator strings.
   *  The written text begins with the string `start` and ends with the string `end`.
   *  Inside, the string representations (w.r.t. the method `toString`)
   *  of all elements of this $coll are separated by the string `sep`.
   *
   * Example:
   *
   * {{{
   *      scala> val a = List(1,2,3,4)
   *      a: List[Int] = List(1, 2, 3, 4)
   *
   *      scala> val b = new StringBuilder()
   *      b: StringBuilder =
   *
   *      scala> a.addString(b , "List(" , ", " , ")")
   *      res5: StringBuilder = List(1, 2, 3, 4)
   * }}}
   *
   *  @param  b    the string builder to which elements are appended.
   *  @param start the starting string.
   *  @param sep   the separator string.
   *  @param end   the ending string.
   *  @return      the string builder `b` to which elements were appended.
   */
  def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = {
    var first = true

    b append start
    for (x <- self) {
      if (first) {
        b append x
        first = false
      }
      else {
        b append sep
        b append x
      }
    }
    b append end

    b
  }

五、Scala Collection(集合)

  • Scala提供了一套很好的集合实现,提供了一些集合类型的抽象。

  • Scala集合分为可变和不可变的集合。

  • 可变集合可以在适当的地方被更新或扩展。这意味着你可以修改、添加、移除一个集合的元素。

  • 而不可变集合类,相比之下,永远不会变。不过,你仍然可以模拟添加、移除、或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。

序号集合及描述
1Scala List(列表) List的特征是其元素以现行方式存储,集合中可以存放重复对象,参考API文档
2Scala Set(集合) Set是最简单的一种集合。集合中的对象不按特定的方式排序,它的每一个元素都包含一对键对象和值对象参考API文档
3Scala Map(映射) Map是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象,参考API文档
4Scala元组 元组是不同类型的值的集合
5Scala Option Option[T] 表示有可能包含值的容器,也可能不包含值
6Scala Iterator1(迭代器) 迭代器不是一个容器,更确切的说是逐一访问容器内元素的方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值