1. 程式人生 > 程式設計 >Scala Class etc. 2

Scala Class etc. 2

Higher-Order Functions

  • def 定義的是方法,而不是函式
  • 函式可作為變數存在,可直接呼叫,也可作為值傳遞給其他函式
  • _ 字尾將普通方法變為函式: ceil _
    • 根據上下文編譯器可以自動將方法轉換為函式,也可省略 _ 字尾
  • 高階函式,接收函式的函式
  • 引數型別推導
    • 匿名函式傳遞給其他函式或方法時,如果一直到引數型別,則可省略匿名函式的引數型別,可自動推導型別
    • 引數只有一個時可省略括號
      • 當引數在右側只出現一次時,可使用 _ 簡寫
  • 閉包 Closures,特定作用域
  • SAM,single abstract method interface
    • 對應 Java 中的函式式介面 (1.8)
    • 可將 Scala 函式傳遞給 Java,只在函式字面量中起作用
  • 柯里化 Currying
    • 將接收兩個引數的函式變為接收第一個引數的函式,該函式返回一個消費第二個引數的函式
  • 控制抽象 Control Abstractions
    • Scala 只包含少量的流程控制語句,使用者可自定義控制語句

Pattern Matching and Case Classes

  • 可對任何型別進行模式匹配,匹配順序從上至下
  • 模式匹配代替 switch,預設分支為 case _;可避免 switch 語句中因缺少 break 帶來的 fall-through 問題
  • 模式匹配也是表示式,可將其返回值直接賦值給變數
  • 模式守衛 / guards,為匹配設定條件,任何 Boolean 條件都可作為模式守衛;case ... if ... => ...
  • case 關鍵字後接變數名或對應資料結構中使用變數名,那麼匹配項就賦值給該變數,變數名必須以小寫字母開頭
  • 使用 | 分隔同一匹配的多個可選項,此時不可使用變數繫結元素
  • 型別匹配,代替 isInstanceOfasInstanceOf,直接進行型別轉換
    • 必須為型別指定變數名,否則匹配的是實際的型別物件
    • 匹配在執行時發生,而 JVM 泛型會被擦除
      • 不可以匹配具體的 Map 型別(可使用 case Map[_,_],不可使用 case Map[Int,Int]
      • Array 的型別不會被擦除
  • 解構 destructuring
    • 匹配陣列
    case Array(x,y) => s"$x $y"  // 匹配長度為2的陣列,並將分別繫結到 x,y
    case Array(0,rest @ _*) => rest.min // 可變引數複製程式碼
  • 匹配 List
    case x :: y :: Nil => ...  // 繫結引數
    case head :: tail => ...  // 解構 head,tail複製程式碼
  • 匹配元組
    case (0,_) => ... // 匹配第一個元素為0
    case (x,y) => ... // 繫結引數複製程式碼
  • 定義變數,注意一定要小寫開頭;其實等價於 match 模式匹配加上賦值操作
    • val (x,y) = (1,2)
    • val Array(f,s,rest @ _*) = arr
  • 用於 for 迴圈遍歷集合,匹配符合條件的元素
  for ((k,v) <- System.getProperties()) println(s"$k $v")
  // 匹配 value 為 "" 的項,其他的則被忽略
  for ((k,"") <- System.getProperties()) println(k)
  // if guard 過濾
  for ((k,v) <- System.getProperties() if v == "") println(k)複製程式碼

  • Case Class
    • 用於模式匹配的特殊類
    • 構造引數預設為 val,預設提供 applyunapplytoStringequalshashCodecopy
      • copy 用於複製物件時,可使用命名引數來修改屬性
    • case class X 使用時 case X() => ...,需要括號
    • case object S 單例,使用時 case S => ..., 不要括號
    • :: 也是 case class,配合中綴表示式,就是常見的匹配方式,case head :: tail,實際呼叫 ::(head,tail)
    • 可用於巢狀的結構;繫結變數、可變引數匹配類似
    • 適用於固定結構的類,如 List
  • sealed 密封的
    • 被修飾的類,則其子類必須和該類在同一個檔案中定義
    • 在編譯時即確定了所有匹配項的可能性
  • Option 也是使用 case class 來表示是否有值存在的
    • 子類 Some 封裝值,子類 None 表示無值
    • 相比使用 ""null 更加安全
    • Map 進行 get 操作返回的也是 Option,也可使用模式匹配來處理
    • getOrElse 嘗試獲取值,未獲取到則使用給定的值
  • Partial Function 偏函式
    • 沒有對所有輸入進行定義的函式
    • apply 從模式匹配中計算函式值,isDefinedAt 判斷輸入是否匹配定義的模式
    • case 語句塊是偏函式
    • PartialFunction[A,B] 的例項, A 為輸入型別,B 為輸出型別
      • 可使用偏函式的 lift 方法,將偏函式變為常規函式,返回值為 Option[B]
      • 也可以通過 Function.unlift 將返回 Option[B] 的函式變為偏函式
    • Seq[A] 也是偏函式 PartialFunction[Int,A]
    • Map[K,V] 也是偏函式 PartialFunction[K,V]
    • catch 語句也是偏函式,可在 catch 塊中使用模式匹配處理異常

註解

  • Scala 中註解可影響程式碼編譯,如 @BeanProperty 會自動生成 getter/setter
  • 可用於 類、方法、欄位、變數、引數等
    • 多個註解無順序
    • 主構造器的註解,需要加括號 class Credential @Inject() (var username: String,var password: String)
    • 表示式的註解,使用分號加註解的方式 (map.get(key): @unchecked) ...
    • 型別引數的註解,class Test[@specialized T]
    • 實際型別的註解,放在型別之後,def name: String @Localized
  • 註解實現
    • 註解必須繼承 Annotation
    • 型別註解必須繼承 TypeAnnotation
    • 元註解 @param,@field,@getter,@setter,@beanGetter,@beanSetter
  • 對應 Java 修飾符、標記介面
    • @volatile 對應 volatile 關鍵字
    • @transient 對應 transient 關鍵字
    • @strictfp 對應 strictfp 關鍵字
    • @native 對應 native 關鍵字
    • @cloneable 對應 Cloneable
    • @remote 對應 java.rmi.Remote
    • @SerialVersionUID 代替序列化欄位
  • 使用 @throws(classOf[Exception]) 來處理 Java 中的受檢異常
  • @varargs 處理可變引數
    • @varargs def name(args: String*) 生成 void name(String... args)
    • 沒有 @varargs 則可變引數會被轉換成 Seq[T]
  • 優化
    • @tailrec 會嘗試優化尾遞迴呼叫,將其變為迴圈
    • @switch 編譯器會檢查 match 表示式是否編譯為 ableswitch` 或 `lookupswitch,如果被編譯成一系列條件表示式,則會丟擲異常
    • @inline,@noinline 建議編譯器是否將方法替換為行內呼叫
    • @elidable,用於標註在生產程式碼中可移除的方法
      • elidable 物件定義了很多級別常量可直接使用,未指定引數時預設是 SERVERE 即 1000(包含1000)
    • @specialized 處理基礎型別,自動生成基礎型別對應包裝類的方法