1. 程式人生 > >scala筆記-隱式轉換與隱式引數(16)

scala筆記-隱式轉換與隱式引數(16)

Scala提供的隱式轉換和隱式引數功能,是非常有特色的功能。是Java等程式語言所沒有的功能。它可以允許你手動指定,將某種型別的物件轉換成其他型別的物件。通過這些功能,可以實現非常強大,而且特殊的功能。 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("leo")
leo.emitLaser
隱式轉換函式作用域與匯入
// Scala預設會使用兩種隱式轉換,一種是源型別,或者目標型別的伴生物件內的隱式轉換函式;一種是當前程式作用域內的可以用唯一識別符號表示的隱式轉換函式。

// 如果隱式轉換函式不在上述兩種情況下的話,那麼就必須手動使用import語法引入某個包下的隱式轉換函式,比如import test._。通常建議,僅僅在需要進行隱式轉換的地方,比如某個函式或者方法內,用iimport匯入隱式轉換函式,這樣可以縮小隱式轉換函式的作用域,避免不需要的隱式轉換。
隱式轉換的發生時機
// 1、呼叫某個函式,但是給函式傳入的引數的型別,與函式定義的接收引數型別不匹配(案例:特殊售票視窗)
// 2、使用某個型別的物件,呼叫某個方法,而這個方法並不存在於該型別時(案例:超人變身)
// 3、使用某個型別的物件,呼叫某個方法,雖然該型別有這個方法,但是給方法傳入的引數型別,與方法定義的接收引數的型別不匹配(案例:特殊售票視窗加強版)

// 案例:特殊售票視窗加強版
class TicketHouse {
  var ticketNumber = 0
  def buySpecialTicket(p: SpecialPerson) = {
    ticketNumber += 1
    "T-" + ticketNumber
  }
}
隱式引數
// 所謂的隱式引數,指的是在函式或者方法中,定義一個用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.")
}