地表最强系列之Scala的扩展

模式匹配

  1. 唱量模式
    常量模式仅匹配自身,任何字面量都可用做常量。
def matchTest(x:Int):String=x match{
	case 1=>"one"
	case 2=>"two"
	case _=>"many"
}
  1. 变量模式
    变量模式类似于通配模式,可以匹配任意对象,不过与通配符不同的是,Scala将变量绑定在匹配的对象上,随后可以使用该变量操作对象。
val expr=10 
expr match { 
  case 0=>println("zero") 
  case x=>println(x)  //变量模式 
} 
  1. 构造器模式
    构造器模式检查对象是否为该名称的样本类实例,并提取构造参数绑定到指定变量中。
    1.样例类的模式匹配
    样例类中,自动实现了 unapply()方法(也称提取器),用于将对象分解为用
    以匹配模式的片段,即该方法接受一个实例对象,返回最初创建它所用的参数。
//定义一个样例类
  case class Student(name:String,age:Int)

  def main(args: Array[String]): Unit = {

    //定义一个样例类的模式匹配
    def matchTest04(x:Student)=x match {
      case Student(name,19) =>println(name+" 1111的年龄是19")
      case Student("Tom",age) => println("Tom的年龄是"+age)
      case Student(name,age)=>println(name,age)
      case _ =>println("no matches")
    }

    val stu1 = Student("zhangsan",19)
   // matchTest04(stu1)
    matchTest04(Student("Tom",19))
    matchTest04(Student("lisi",20))

2.非样例类的匹配模式
普通类也可以使用模式匹配,前提是实现了提取器。
提取器返回的是 Option 类型,该类型有两种形式:
➢ Some(x):表示有值,x 是实际值
➢ None:表示无值
Some 和 Node 均是 Option 的子类。

class Student(_name:String,_age:Int) { 
  var name=_name 
  var age=_age 
} 
object Student{   
  def unapply(arg: Student): Option[(String, Int)] ={ 
    if(arg==null) None else Some(arg.name,arg.age)  //实现提取器 
  } 
} 
def matchTest(x:Student)=x match { 
    //应用提取器 Student.unapply(x) 
    case Student(n,a) => println(n,a)   
} 
matchTest(new Student("Jason",19))   //输出:(Jason,19)
  1. 类型模式
def matchTest3(x: Any): String = x match { 
  case x:Int => "Int" 
  case x:String => "String" 
  case _ => "Any" 
} 
matchTest3(3.0)   // Any 
matchTest3(1)     // Int 
  1. 模式守卫
    模式守卫与 for 循环守卫用法类似,用于限制模式的匹配规则。守卫可以是引用模式中的任意布尔表达式,如果有守卫,只有在守卫返回 true 时才匹配成功。
def matchTest2(x: Int): String = x match { 
  case i if i==1 => "one" 
  case i if i==2 => "two" 
  case _ => "many" 
} 
matchTest2(3)  // many 
matchTest2(1)  // one 

偏函数

偏函数是只对函数定义域的一个子集进行定义的函数。举例来说,List 中可能存在不同类型的元素:List(1,2,3,“four”),假设现在需要对数字进行加 1 操作:

List(1,2,3,"four").map(x=>if(x.isInstanceOf[Int]) x.asInstanceOf[Int]+1 else x) 
//输出 List(2,3,4,"four") 

对于普通函数,需要考虑所有输入参数的情况,也就是说,对于函数 A => B,它对 A 类型的所有值都有意义;而偏函数PartialFunction[A, B]仅对 A 类型的部分值有意义。
使用偏函数实现上面需求的代码如下:

val pf:PartialFunction[Any, Int]={case x:Int=>x+1} 
List(1,2,3,"four").collect(pf)  //输出 List(2,3,4) 

可以发现,对于偏函数 pf 来说,对 Any 类型所有值仅处理了符合要求(x:Int)的 Int 数据,返回 Int 类型。通常偏函数不需单独定义,类似下面用法:

List(1,2,3,"four").collect({case x:Int=>x+1})  //输出List(2,3,4) 
List(1,2,3,"four").collect{case x:Int=>x+1}   //可省略函数小括号 

其中,“{ case pattern=> ??? }”表达式是一个整体,包括外面的大括号。这里 case 后面的写法与模式匹配完全相同,可以为不同的匹配模式。为了方便描述,统称为 case 语句、或者函数字面量。
可以认为,一个 case 语句就是一个独立的匿名函数,如果有一组 case 语句的话,从效果上看,构建出的这个匿名函数会有多种不同的参数列表,每一个case 对应一种参数列表,参数是 case 后面的变量声明,其值是通过模式匹配赋
予的。例如:

List(1,2,3,"four").map{case x:Int=>x+1;case x:String=>x}    //类型模式  
List(1,2,3).map{case 1=>"one";case 2=>"two";case 3=>"three"} //常量模式 

实际上,case 语句返回的是一个特质 PartialFunction(继承自(A=>B)),其本质还是一个函数(scala.Function1),所以当成函数用没有一点问题。
但是反过来,普通函数当成偏函数使用就不可以
case 语句是创建 PartialFunction 的便捷方式,原始自定义创建 PartialFunction方式如下。

//自定义一个偏函数
  val pf1: PartialFunction[Any, Int] = new PartialFunction[Any, Int] {
    override def isDefinedAt(x: Any): Boolean = {
      //判断是不是int类型,如果是int,我们就对它进行处理
      if (x.isInstanceOf[Int]) true else false
    }

    override def apply(v1: Any): Int = {
      v1.asInstanceOf[Int] + 10
    }
  }

   val list = List(1,2,3,4,"five")

PartialFunction 特质规定了两个要实现的方法:apply 和 isDefinedAt。
1)isDefinedAt 用来告知调用方这个偏函数接受参数的范围,可以是类型也可以是值,在我们这个例子中我们要求这个 inc 函数只处理 Int 型的数据。
2)apply 方法用来描述对已接受的值如何处理,在我们这个例子中,我们只是简单的把值+1,注意,非 Int 型的值已被 isDefinedAt 方法过滤掉了,所以不用担心类型转换的问题

正则表达式

  1. 使用 String 类的 matches()方法
"1123".matches("[a-zA-Z0-9]{4}")
  1. 模式匹配
    先定义规则,再通过模式匹配的方式来匹配
//模式匹配
//使用“.r”方法可使任意字符串变成一个Regex实例
   val re: Regex = "[a-zA-Z][0-9][a-zA-Z] [0-9][a-zA-Z][0-9]".r
  "L3R 6M2" match {
    case re(x)=>println("valid zip-code:"+x)
    case x=>println("invalid zip-code:"+x)
  }

3.使用 Regex(scala.util.matching.Regex)的提取器进行模式匹配
findFirstMatchIn() 返回第一个匹配(Option[Match])
findAllMatchIn() 返回所有匹配结果(Regex.Match)
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")   //未匹配
}
  1. 捕获分组
    识别“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)}")
}
  1. 字符串替换
//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 
  1. 在字符串中查找模式
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")
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值