scala扩展

一.模式匹配

1.match表达式

  • 类似Java switch语句
  • 能处理任何类型
  • 不需要break
  • 能够生成值
//基本模式匹配
def matchTest(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "many"
}
matchTest(3)  // many
matchTest(1)  // one
//模式守卫(在模式后面加上if 条件)
def matchTest2(x: Int): String = x match {
  case i if i==1 => "one"
  case i if i>2 => "大于2"
  case _ => "many"
}
matchTest2(3)  // 大于2
matchTest2(1)  // one
//仅匹配类型
def matchTest3(x: Any): String = x match {
  case x:Int => "Int"
  case x:String => "String"
  case _ => "Any"
}
matchTest3(3.0)  // Any
matchTest3(1)     // Int

2.样例类的模式匹配

  • 模式匹配:检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分
//样例类的模式匹配
def matchTest4(x: Student)= x match {
  case Student(name,19) => println(name)
  case Student("Tom",age) => println(age)
  case Student(name,age) => println(name,age)
  case _ => println("no matches")
}
matchTest4(Student("Jason",19))
matchTest4(Student("Tom",20))
matchTest4(Student("Jimmy",20))

3.非样例类的模式匹配

  • 单例对象中指定unapply()方法时,称为提取器对象(Extractor Objects)
  • unapply()方法接受一个实例对象,返回最初创建它所用的参数
class Student(_name:String,_age:Int) {
  var name=_name
  var age=_age
}
object Student{
  def apply(name: String, age: Int): Student = new Student(name, age)
  def unapply(arg: Student): Option[(String, Int)] ={
    if(arg==null) None else Some(arg.name,arg.age)  
  }
}
def matchTest(x:Student)=x match {
    case Student(name,age) if age<=20 => println("young man")
    case Student(name,age) if age>20 => println("old man")
}
matchTest(Student("Jason",19))   //young man

二.偏函数

偏函数是只对函数定义域的一个子集进行定义的函数

  • PartialFunction[-A,+B]是一个特质
  • A为函数定义域,B为偏函数返回值类型
  • apply()
  • isDefinedAt()
//自定义偏函数
val inc = new PartialFunction[Any, Int] {
    def apply(any: Any) = any.asInstanceOf[Int]+1
    def isDefinedAt(any: Any) = 
                                  if (any.isInstanceOf[Int]) true else false
}
List(1,2,3,"four").collect(inc)
  • case语句
val pf:PartialFunction[Any, Int]={case x:Int=>x+1} //返回一个偏函数
List(1,2,3,"four").collect(pf)  //输出List(2,3,4)

三.注解 Annotation

  • Scala标准库注解包——scala.annotation
  • 注解语法:@注解名称(注解参数...)
//常用注解
@throws@deprecated@unchecked@SerialVersionUID……
  • 可使用注解的地方:类、方法、方法参数、字段、局部变量
object DeprecationDemo extends App{
  @deprecated("deprecation message", "release # which deprecates method")
  def hello = "hola"
  @throws(classOf[Exception])
  def test(){}  
}

四.运算符

  • 在Scala中,运算符即是方法。任何具有单个参数的方法都可以用作中缀运算符
10.+(1)
10 + 1

定义和使用运算符

  • 1)算数运算符
  • 2)关系运算符
  • 3)逻辑运算符
  • 4)赋值运算符
  • 5位运算符
case class Vec(val x: Double, val y: Double) {
  def +(that: Vec) = new Vec(this.x + that.x, this.y + that.y)
  def add(that: Vec) = new Vec(this.x + that.x, this.y + that.y)
}
val vector1 = Vec(1.0, 1.0)
val vector2 = Vec(2.0, 2.0)
val vector3 = vector1 + vector2  // 或者 vector1 add vector2
vector3.x  // 3.0
vector3.y  // 3.0

五.scala正则表达式

Scala支持多种正则表达式解析方式

  • String.matches()方法
  • 正则表达式模式匹配
  • scala.util.matching.Regex API
//String.matches
"!123".matches("[a-zA-Z0-9]{4}")  //false
"34Az".matches("[a-zA-Z0-9]{4}")  //true

//模式匹配,Regex实现了提取器
val ZipcodePattern = "([a-zA-Z][0-9][a-zA-Z] [0-9][a-zA-Z][0-9])".r//使用“.r”方法可使任意字符串变成一个Regex实例
"L3R 6M2" match {
    case ZipcodePattern(zc) => println("Valid zip-code: " + zc )  //zc为第1个分组结果,可以匹配多个分组
    case zc => println("Invalid zip-code: " + zc )
} 

scala.util.matching.Regex

  • findFirstMatchIn() 返回第一个匹配(Option[Match])
  • findAllMatchIn() 返回所有匹配结果(Regex.Match) 调用了findAllIn的方法
  • findAllIn() 返回所有匹配结果(String迭代器)
import scala.util.matching.Regex
val numberPattern: Regex = "[0-9]".r
numberPattern.findFirstMatchIn("awesomepassword") match {
  case Some(_) => println("Password OK")  //匹配成功
  case None => println("Password must contain a number")   //未匹配
}

捕获分组:识别“name:Jason,age:19,……”中的键值对

import scala.util.matching.Regex

val studentPattern:Regex="([0-9a-zA-Z-#() ]+):([0-9a-zA-Z-#() ]+)".r
val input="name:Jason,age:19,weight:100"

for(patternMatch<-studentPattern.findAllMatchIn(input)){
    println(s"key: ${patternMatch.group(1)} value: ${patternMatch.group(2)}")
}

字符串替换

//search
val nums = "[0-9]+".r.findAllIn("123 Main Street Suite 2012")
nums.next   // -> 123
nums.next  // -> 2012

//replace
"[0-9]+".r.replaceFirstIn("234 Main Street Suite 2034", "567") //234->567   
"[0-9]+".r.replaceAllIn("234 Main Street Suite 2034", "567") //234、2034->567  

在字符串中查找模式

val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
"2014-05-23" match {
    case date(year, month, day) => println(year,month,day)
}
"2014-05-23" match {
    case date(year, _*) => println("The year of the date is " + year) 
} 
"2014-05-23" match {
    case date(_*) => println("It is a date")
}

六.隐式类

隐式转换

  • 隐式参数、隐式函数
  • 隐式转换函数是以implicit关键字声明的带有单个参数的函数
  • 这种函数将会自动应用,将值从一种类型转换到另一种类型

隐式类

  • 用implicit关键字修饰的类,其主构造器可用于隐式转换
  • 只能在类、Trait、对象(单例对象、包对象)内部定义
  • 构造器只能携带一个非隐式参数
  • 隐式类不能是case class
  • 在同一作用域内,不能有任何方法、成员或对象与隐式类同名

隐式类应用

  • 为String对象增加新的方法
object Stringutils {
  implicit class StringImprovement(val s:String){//隐式类
  def increment=s.map(x=>(x +1).toChar)
  }
}
object Main extends App{
  import Stringutils._
  println("mobin".increment)	//输出:npcjo
}

七.Scala异常处理

抛出异常

 throw new 异常类型

捕获异常

try{
  //todo
}catch{
  case ex:异常类型=>{ //todo }
  ……
}finally{
  //todo
}
  • 示例:
try {
      val f=new File("input.txt")
      if(!f.canWrite)
        throw new Exception("file can't write")
      val file=Source.fromFile(f);
      for(line<-file.getLines()) println(line)
} catch {
      case ex: FileNotFoundException => {
        println("Missing file exception")
      }
      case ex: IOException => {
        println("IO Exception")
      }
      case ex: Exception => {
        println(ex.getMessage)
      }
} finally {
      println("Exiting finally...")
}

使用Either处理异常

  • Either[A, B] 表示要么包含一个类型为A的实例,要么包括一个类型为B的实例
  • Either只有两个子类型:Left、Right,如果Either[A, B]对象包含的是A的实例,则它是Left实例,否则是Right实例
  • Either用于异常处理时,一般约定:Left 代表出错的情况,Right 代表成功的情况
def divide(x:Int): Either[String,Int] ={
  if(x==0)
    Left("除数不能为0")
  else
    Right(100/x)
}
def test(x:Int)=divide(x) match {
    case Left(errMsg)=>println(errMsg)
    case Right(result)=>println(result)
}
test(0)
test(1)

allCatch

scala.util.control.Exception.allCatch.opt("42".toInt)      // Some(42)
scala.util.control.Exception.allCatch.opt("42a".toInt)    // None

scala.util.control.Exception.allCatch.toTry("42".toInt)  // 42
scala.util.control.Exception.allCatch.toTry("42a".toInt)  // Failure (e)

scala.util.control.Exception.allCatch.withTry("42".toInt)  // Success(42)
scala.util.control.Exception.allCatch.withTry("42a".toInt)  // Failure (e)

scala.util.control.Exception.allCatch.either("42".toInt)  // Right(42)
scala.util.control.Exception.allCatch.either("42a".toInt)  // Left(e)

failAsValue 发生异常时使用缺省值

scala.util.control.Exception.failAsValue(classOf[Exception])(-9999)("42a".toInt)

八.Scala高级类型

  • 结构类型:指一组关于抽象方法、字段和类型的规格说明
//定义结构类型
{
    def sayHello(name:String):Unit
}
//结构类型作为函数参数
def f(a:{def sayHello():Unit}){a.sayHello}
//函数调用
f(new {def sayHello():Unit={println("hello")}})
  • 复合类型可以由多个对象类型构成,主要用于缩短已有对象成员的签名,格式为:A with B with C … { refinement }
trait X1 
trait X2
//定义复合类型参数x
def test(x: X1 with X2) = {println("ok")}
//函数调用,实参为匿名对象
test(new X1 with X2)
object A extends X1 with X2
//实参为单例对象
test(A)
  • Scala集成Java API
需求
在Scala中使用Java API计算今天、昨天……等日期
分析
java.text.SimpleDateFormat
java.util.Calendar
java.util.Date
import java.text.SimpleDateFormat
import java.util.{Calendar, Date}
val dateFmt = "yyyy-MM-dd"
def today(): String = {
    val date = new Date
    val sdf = new SimpleDateFormat(dateFmt)
    sdf.format(date)
}

练习题

/*练习1需求说明
使用样例类实现Book
使用模式匹配输出每本书的title与authors
*/
case class Book(var title:String= "",var authors:String= "")
object Book{
  def apply(title:String,authors:String*): Book = new Book(title,authors.mkString(" "))
}
object Practice extends App {
  def matchBook(x:Book):String= x match {
    case Book(title, "张三 李四")=>"书名:"+title+" 相关作者:"+
      Book(title, "张三 李四").authors
    case Book(title, authors)=>"书名:"+title+" 相关作者:"+authors
  }
    private val books = List[Book](Book("西游记","张三","李四"),
      Book("红楼梦","王五","申九"),
      Book("水浒传","申九","宫八"))
  books.foreach(x=>println(matchBook(x)))
}

/*练习2需求说明
现有如下日志信息,请使用Scala正则表达式解析如下信息
日志级别
日期
请求URI
INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=31
INFO 2016-07-25 requestURI:/c?app=0&p=2&did=18005472&industry=469&adid=31
INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=32
*/
object Practice02 extends App {
  val pattern = ("^(\\w+)\\s(\\d{4}-\\d{2}-\\d{2})\\s(\\w+)" +
    "(:(/\\w+)([\\?&]\\w+=\\w+)+)$").r
  val list = List("INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=31","INFO 2016-07-25 requestURI:/c?app=0&p=2&did=18005472&industry=469&adid=31","INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=32")
  list.foreach(x=>pattern.findAllMatchIn(x).foreach(y=>println(s"日志级别-->${y.group(1)} 日期-->${y.group(2)} URI地址-->${y.group(3)}${y.group(4)}")))
}
  • 效果如下
  • 练习1
    在这里插入图片描述
  • 练习2

在这里插入图片描述

/*编写 Scala 程序,使用正则表达式找出某个网页中所有 img 标签的 src 属性。
提示:scala.io.Source.fromURL()可以下载网页内容。*/
object RegexDemo04 extends App {
  private val source = scala.io.Source.fromURL("https://blog.csdn.net/sun_0128/article/details/107706599").mkString
  val pattern = """<img[^>]+(src\s*=\s*"[^>^"]+")[^>]*>""".r
  pattern.findAllIn(source).foreach(println(_))
}
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页