1. 程式人生 > >Spark基礎-scala學習(八、隱式轉換與隱式引數)

Spark基礎-scala學習(八、隱式轉換與隱式引數)

大綱

  1. 隱式轉換
  2. 使用隱式轉換加強現有型別
  3. 匯入隱式轉換函式
  4. 隱式轉換的發生時機
  5. 隱式引數

隱式轉換

  1. 要實現隱式轉換,只要程式可見的範圍內定義隱式轉換函式即可。Scala會自動使用隱式轉換函式。隱式轉換函式與普通函式唯一的語法區別就是,要以implicit開頭,而且一定要定義函式返回型別
  2. 案例:特殊售票視窗(只接受特殊人群,比如學生、老人等)
scala> :paste
// Entering paste mode (ctrl-D to finish)

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
}

// Exiting paste mode, now interpreting.

<pastie>:15: warning: implicit conversion method object2SpecialPerson should be enabled
by making the implicit value scala.language.implicitConversions visible.
This can be achieved by adding the import clause 'import scala.language.implicitConversions'
or by setting the compiler option -language:implicitConversions.
See the Scaladoc for value scala.language.implicitConversions for a discussion
why the feature should be explicitly enabled.
implicit def object2SpecialPerson(obj:Object):SpecialPerson = {
             ^
defined class SpecialPerson
defined class Student
defined class Older
object2SpecialPerson: (obj: Object)SpecialPerson
ticketNumber: Int = 0
buySpecialTicket: (p: SpecialPerson)String

scala> val s = new Student("leo")
s: Student = 
[email protected]
scala> buySpecialTicket(s) res0: String = T-1 scala> val o = new Older("Jike") o: Older = [email protected] scala> buySpecialTicket(o) res1: String = T-2

使用隱式轉換加強現有型別

  1. 隱式轉換可以在不知不覺中加強現有型別的功能。也就是說,可以為某個類定義一個加強版的類,並定義互相之間的隱式轉換,從而讓源類在使用加強版的方法時,由scala自動進行隱式轉換為加強類,然後再呼叫該方法
  2. 案例:超人變身
scala> :paste
// Entering paste mode (ctrl-D to finish)

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)


// Exiting paste mode, now interpreting.

defined class Man
defined class Superman
man2superman: (man: Man)Superman

scala> val leo = new Man("leo")
leo: Man = 
[email protected]
scala> leo.emitLaser emit a laster!

隱式轉換函式的作用域與匯入

  1. scala會使用兩種隱式轉換,一種是源型別,或者目標型別的伴生物件內的隱式轉換函式;一種是當前程式作用域內的可以用唯一識別符號表示的隱式轉換函式
  2. 如果隱式轉換函式不在上述兩種情況下的話,那麼就必須手動使用import語法引入某個包下的隱式轉換函式,比如import test._ 通常建議,僅僅在需要進行隱式轉換的地方,比如某個函式或者方法內,用import匯入隱式轉換函式,這樣可以縮小隱式轉換函式的作用域,避免不需要的隱式轉換。

隱式轉換的發生時機

  1. 呼叫某個函式,但是給函式傳入的引數的型別,與函式定義的接收引數型別不匹配(案例:特殊售票視窗)
  2. 使用某個型別的物件,呼叫某個方法,而這個方法並不在於該型別時(案例:超人變身)
  3. 使用某個型別的物件,呼叫某個方法,雖然該型別有這個方法,但是給方法傳入的引數型別,與方法定義的接收引數的型別不匹配(案例:特殊售票視窗加強版)
  4. 案例:特殊售票視窗加強版
scala> :paste
// Entering paste mode (ctrl-D to finish)

class TicketHouse {
 var ticketNumber= 0
 def buySpecialTicket(p:SpecialPerson) = {
  ticketNumber += 1
  "T-"+ticketNumber
 }
}

// Exiting paste mode, now interpreting.

defined class TicketHouse

scala> val leo = new Student("leo")
leo: Student = [email protected]

scala> val ticket = new TicketHouse
ticket: TicketHouse = [email protected]

scala> ticket.buySpecialTicket(leo)
res1: String = T-1

隱式引數

  1. 所謂的隱式引數,指的是在函式或者方法中,定義一個用implicit修飾的引數,此時Scala會嘗試找到一個指定型別的,用implicit修飾的物件,即隱式值,並注入引數
  2. Scala會在兩個範圍內查詢:一種是當前作用域內可見的val或var定義的隱式變數;一種是隱式引數型別的伴生物件內的隱式值
  3. 案例:考試簽到
scala> :paste
// Entering paste mode (ctrl-D to finish)

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.")
}

// Exiting paste mode, now interpreting.

defined class SignPen
signPen: SignPen = [email protected]
signForExam: (name: String)(implicit signPen: SignPen)Unit

scala> signForExam("leo")(signPen)
leo come to exam in time.