2019年9月6日 星期五

Scala 2.x 五 泛型、隱式轉換

※泛型類別、泛型方法

def genericMethod[T](t: T, list: List[T]): Unit = {}

class Chicken[T] extends Bird {
  def genericMethod(t: T, list: List[T]): Unit = {}
}

※寫在類別名稱或方法名稱後面



※傳參

class Animal{}
class Bird extends Animal{}
class Chicken extends Bird{}


def main(args: Array[String]): Unit = {
  val listA = List[Animal](new Animal)
  val listB = List[Bird](new Bird)
  val listC = List[Chicken](new Chicken)
  xxx(listA, listB, listC)
}

def xxx(a: List[Animal], b: List[Bird], c: List[Chicken]): Unit = {
  // ooo(a)
  ooo(b)
  ooo(c)
}

def ooo[T](list: List[Bird]) {}



※賦值

val listA = ListBuffer[Animal](new Animal)
val listB = ListBuffer[Bird](new Bird)
val listC = ListBuffer[Chicken](new Chicken)

val a = new Animal()
val b = new Bird()
val c = new Chicken()

listA += a
listA += b
listA += c

//    listB += a
listB += b
listB += c

//    listC += a
//    listC += b
listC += c


※以上都和 java 一樣

※沒有通配符「?」




※<:、>:


<::類似 java 的 extends
>::類似 java 的 super
.只能跟著自定義名稱,如 T

val listA = ListBuffer[Animal](new Animal)
    val listB = ListBuffer[Bird](new Bird)
    val listC = ListBuffer[Chicken](new Chicken)
    ooo(listA)
    ooo(listB)
//    ooo(listC)


def ooo[T >: Bird](listBuffer: ListBuffer[T]) = {}



※+T、-T

如果只有 T,沒有辦法將子類轉成父類或父類轉成子類

class GenericTest[T](t: T){} // +T、-T

class Animal{}
class Bird extends Animal{}
class Chicken extends Bird{}



.+T:表示子類可轉成父類

val a = new GenericTest[Animal](new Animal())
val b = new GenericTest[Bird](new Bird())
val c = new GenericTest[Chicken](new Chicken())

val d:GenericTest[Animal]  = b
val f:GenericTest[Bird]  = c
val e:GenericTest[Animal]  = c


.-T:表示父類可轉成子類

val a = new GenericTest[Animal](new Animal())
val b = new GenericTest[Bird](new Bird())
val c = new GenericTest[Chicken](new Chicken())

val d:GenericTest[Chicken]  = b
val f:GenericTest[Bird]  = a
val e:GenericTest[Chicken]  = a



※隱式轉換


.隱式方法

def printStr(data: String): Unit = println(data)

//  implicit def int2Str(i: Int):String = i + "xxx"
implicit def intToStr(j: Int):String = j.toString
// -------------------
printStr("abc")
printStr(123)

※用 java 的 overloading 也可以做到轉換的功能,但這裡說的是 scala 的隱式轉換

※如果沒有 implicit 的方法時,給 int 會編譯錯誤

※printStr 要的是 String 參數,但給的是 int,所以會去找參數是 int,回傳是 String 的隱式方法,如果有兩個(含)以上會報錯


再一個例子:
class Animal(name: String) {
  private var iname: String = ""

  def sname = name
  def sname_=(name: String): Unit = {
    this.iname = name
  }
}

class Bird(name: String) {
  private var iname: String = ""

  def sname = name
  def sname_=(name: String): Unit = {
    this.iname = name
  }
}

※兩個類別,然後給 getter/setter 方法

def printNameOfAnimal(animal: Animal): Unit = println(animal.sname)

implicit def birdToAnimal(b: Bird): Animal = {
new Animal("b" + b.sname)
}
// -------------------
printNameOfAnimal(new Animal("chicken"))
printNameOfAnimal(new Bird("chicken"))



.隱式值

object ScalaTest {
  implicit val xxx = new Animal("qoo")

  def main(args: Array[String]): Unit = {
    xxx("x")
  }

  def xxx(name: String)(implicit a: Animal): Unit = {
    println(a.sname)
  }

  class Animal(name: String) {
    private var iname: String = ""

    def sname = name
    def sname_=(name: String): Unit = {
      this.iname = name
    }
  }
}

※有了隱式值了以後,呼叫 xxx 方法可以不用參數,當然 xxx 方法也要有 implicit 關鍵字

※如果值在其他的類別,就需要 import


.隱式參數

def printStr(implicit data: String, num: Int): Unit = println(data, num)
// def printStr[T <% String](data: String, num: Int): Unit = println(data, num)
implicit def intToStr(j: Int):String = j.toString

printStr("abc", 7)
printStr(123, 7)

※這裡的隱式參數,雖然不寫也能找得到

※還可以用隱式視圖「<%」,但 IDE 提示我已經 deprecated 了,用隱式參數取代



.隱式類別

def main(args: Array[String]): Unit = {
  println(new Animal("xxx").show())
  println("qoo".show())
}

implicit class Animal(name: String) {
  def show(): String = {
    name
  }
}

※第二個 println 原本是不行的,但因為有隱式類別所以可以用

※隱式類別只能有一個參數,太多太少都不行

沒有留言:

張貼留言