Scala 【 14 隱式轉換與隱式參數 】

隱式轉換與隱式參數

​ Scala 的隱式轉換,其實最核心的就是定義隱式轉換函數,即 implicit conversion function 。

​ 定義的隱式轉換函數,只要在編寫的程序內引入,就會被 Scala 自動使用。

​ Scala 會根據隱式轉換函數的簽名,在程序中使用到隱式轉換函數接收的參數類型定義的對象時,會自動將其傳入隱式轉換函數,轉換爲另外一種類型的對象並返回。這就是“隱式轉換”。

​ 隱式轉換函數叫什麼名字是無所謂的,因爲通常不會由用戶手動調用,而是由 Scala 進行調用。但是如果要使用隱式轉換,則需要對隱式轉換函數進行導入。因此通常建議將隱式轉換函數的名稱命名爲 “one2one” 的形式。

隱式轉換

​ 要實現隱式轉換,只要程序可見的範圍內定義隱式轉換函數即可。Scala 會自動使用隱式轉換函數。

​ 隱式轉換函數與普通函數唯一的語法區別就是,要以 implicit 開頭,而且最好要定義函數返回類型。

// 特殊售票窗口(只接受特殊人羣,比如學生、老人等)
class SpecialPerson(val name:String)
class Student(val name:String)
class Older(val name:String)

implicit def object2SpecialPerson(obj:Object):SpecialPerson = {
    if(obj.getClass == classOf[Student]){
        val stu = obj.asInstanceOf[Student];
        new SpecialPerson(stu.name)
    }
    else if(obj.getClass == classOf[Older]){
        val older = obj.asInstanceOf[Older];
        new SpecialPerson(older.name)
    }
    else Nil

var ticketNumber = 0
def buySpecialTicket(p:SpecialPerson) = {
    ticketNumber += 1
    "T - "+ ticketNumber
}
使用隱式轉換加強現有類型

​ 隱式轉換非常強大的一個功能,就是可以在不知不覺中加強現有類型的功能。也就是說,可以爲某個類定義一個加強版的類,並定義互相之間的隱式轉換,從而讓源類在使用加強版的方法時,由Scala自動進行隱式轉換爲加強類,然後再調用該方法。

class Man(val name: String)
class Superman(val name: String) {
  def emitLaser = println("emit a laster!")
}

implicit def man2superman(man: Man): Superman = new Superman(man.name)

val leo = new Man("Li")
Li.emitLaser

隱式轉換函數作用域與導入

​ Scala 默認會使用兩種隱式轉換,一種是源類型,或者目標類型的伴生對象內的隱式轉換函數;一種是當前程序作用域內的可以用唯一標識符表示的隱式轉換函數。

​ 如果隱式轉換函數不在上述兩種情況下的話,那麼就必須手動使用 import 語法引入某個包下的隱式轉換函數,比如 import test._ 。

​ 通常建議,僅僅在需要進行隱式轉換的地方,比如某個函數或者方法內,用import 導入隱式轉換函數,這樣可以縮小隱式轉換函數的作用域,避免不需要的隱式轉換。

隱式轉換的發生時機
  • 調用某個函數,但是給函數傳入的參數的類型,與函數定義的接收參數類型不匹配。
  • 使用某個類型的對象,調用某個方法,而這個方法並不存在於該類型時。
  • 使用某個類型的對象,調用某個方法,雖然該類型有這個方法,但是給方法傳入的參數類型,與方法定義的接收參數的類型不匹配。
隱式參數

​ 所謂的隱式參數,指的是在函數或者方法中,定義一個用 implicit 修飾的參數,此時 Scala 會嘗試找到一個指定類型的,用 implicit 修飾的對象,即隱式值,並注入參數。
​ Scala 會在兩個範圍內查找:一種是當前作用域內可見的 val 或 var 定義的隱式變量;一種是隱式參數類型的伴生對象內的隱式值。

class SignPen{
    def write(content:String) = println(content)
}

implicit val signPen = new SignPen

def signForExam(name:String)(implicit signPen:SignPen){
    signPen.write(name + " come to exam in time.")
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章