Scala Types 2

存在類型

  • 形式: forSome { type ... }forSome { val ... }
  • 主要爲了兼容 Java 的通配符
  • 示例編程

    Array[_]
    // 等價於
    Array[T] forSome { type T}
    
    Map[_, _]
    // 等價於
    Map[T, U] forSome { type T; type U <: T}

類型系統

類型 語法
Class/Trait class C, trait T
元組 (T1, T2...)
函數 (P1, P2...) => T
註解 T @A
參數類型 A[T1, T2...]
單例類型 value.type
類型投射 O#I
組合類型 T1 with T2 ...
中綴類型 T1 A T2
存在類型 T forSome { type/val... }

以上類型可在編寫程序時定義,Scala 也有少許的類型在編譯器內部使用函數

def square(x: Int) = x * x
// REPL 中返回的類型爲
// square(x: Int) Int 
// 省略的方法定義的 =>

自身類型 self type

  • 形式:this: Type =>
  • 用於限制 trait 只能被混編於指定類型的子類中this

    trait T1 { def m1()}
    
    trait T2 extends T1 {
        this: Super1 with Super2 =>
            def m1() { methodInSuper() }
    }
    
    // 使用時只能在 Super1,Super2 的子類中混編 with T2
  • 引入的問題:自身類型不會自動繼承,必須在子類中重複定義scala

    trait T3 extends T2 {
        this: Super1 with Super2 => // 必須重複定義
    }

依賴注入

  • 經過 trait 和 自身類型 實現簡單的以來注入
    • 須要將全部的依賴都組合起來
    trait Logger { def log(msg: String) }
    
    trait Auth {
      this: Logger =>
        def login(id: String, password: String): Boolean
    }
    
    trait App {
      this: Logger with Auth =>
      // ...
    }
    
    object MyApp extends App with FileLogger("test.log") with MockAuth("users.txt")
  • 蛋糕模式 (cake pattern) 實現依賴注入
    • 依賴的組件使用自身類型來表示
    • trait 描述服務接口
    • val 定義須要實例化的服務
    • 層級化組合各個組件,在一個總體中注入須要的組件
    // 定義組件1
    trait LoggerComponent {
      // 描述接口
      trait Logger { ... }
      // 須要實例化的服務
      val logger: Logger
      // 接口具體實現
      class FileLogger(file: String) extends Logger { ... }
      ...
    } 
    
    // 定義組件2
    trait AuthComponent {
      // 自身類型限定混編使用的類型
      this: LoggerComponent => // Gives access to logger
      // 定義服務接口
      trait Auth { ... }
      // 須要實例化的服務
      val auth: Auth
      // 接口具體實現
      class MockAuth(file: String) extends Auth { ... }
      ...
    }
    // 全部的依賴都集中在一處進行配置/注入
    object AppComponents extends LoggerComponent with AuthComponent {
      // 實例化服務/注入
      val logger = new FileLogger("test.log")
      val auth = new MockAuth("users.txt")
    }

    Scala編程的蛋糕模式和依賴注入code

抽象類型

  • 形式: type Name
  • classtrait 中定義
  • 場景:具體類型須要在子類中肯定繼承

    trait Reader {
      type Contents
      def read(fileName: String): Contents
    }
    // 子類實現是具體肯定類型
    class StringReader extends Reader {
      type Contents = String
      def read(fileName: String) = ...
    } 
    
    class ImageReader extends Reader {
      type Contents = BufferedImage
      def read(fileName: String) = ...
    }
  • 抽象類型、類型參數的使用選擇
    • 在類實例化時須要具體確認類型的場景使用類型參數,如 HashMap[String, Int]
    • 指望子類提供具體類型的場景使用抽象類型,如上例中的 Reader
相關文章
相關標籤/搜索