大資料——Scala擴充套件

蜂蜜柚子加苦茶發表於2020-10-25

match表示式

類似於Java switch語句

  • 能處理型別所有型別
  • 不需要break
  • 能夠生成值
val firstArg=if(args.length>0) args(0) else ""
firstArg match{
    case "salt" => println("pepper")
    case "chips" => println("salsa")
    case "eggs" => println("bacon")
    case _ => println("huh?")	//以上未列出的值,使用“_”表示
}

樣例類的模式匹配

模式匹配

  • 檢查某個值(value)是否匹配某一個模式的機制,一個成功的匹配同時會將匹配值解構為其組成部分
//基本模式匹配
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 => "two"
  case _ => "many"
}
matchTest2(3)  // many
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
//僅匹配型別
def matchTest3(x: Any): String = x match {
  case x:Int => "Int"
  case x:String => "String"
  case _ => "Any"
}
matchTest3(3.0)  // Any
matchTest3(1)     // Int

非樣例類的模式匹配

單例物件中指定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()
  • isDefindAt()
//自定義偏函式
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)

註解

Scala標準庫註解包——scala.annotation
註解語法
可使用註解的地方

@註解名稱(註解引數...)
常用註解
@throws、@deprecated、@unchecked、@SerialVersionUID……
  • 類、方法、方法引數、欄位、區域性變數
// An highlighted block
var foo = 'bar';
// An highlighted block
var foo = 'bar';

運算子

在Scala中,運算子即是方法。任何具有的單個引數的方法都可以用作中綴運算子

10.+(1)->10+1

定義和使用運算子

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.match()方法
  • 正規表示式模式匹配
  • 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正規表示式(二)

scala.util.matching.Regex

  • findFirstMatchln()返回第一個匹配(Option[Match])
  • findAllMatchln()返回所有匹配結果(Regex.)
  • findAllln()返回所有匹配結果(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")   //未匹配
}

Scala正規表示式(三)

捕獲分組

  • 識別"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)}")
}

Scala正規表示式(四)

字串替換

//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  

Scala正規表示式(五)

字串中查詢模式

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關鍵字修飾的類,其主構造器可用於隱式轉換

     只能在類、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)

Scala異常處理(三)

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")}})

Scala高階型別(二)

複合型別可以由多個物件型別構成,主要用於縮短已有物件成員的簽名

  • 格式為: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)
}

相關文章