【Scala類型系統(tǒng)】隱式轉(zhuǎn)換與隱式參數(shù)

隱式轉(zhuǎn)換

隱式轉(zhuǎn)換是使用implicit修飾的帶有單個參數(shù)的普通函數(shù)。這種函數(shù)將自動應(yīng)用猫十,將值從一種類型轉(zhuǎn)換為另一種類型然爆。
舉例說明:

我們想將整數(shù)n轉(zhuǎn)換為分?jǐn)?shù)n/1,
定義implicit def int2Fraction(n: Int) = Fraction(n, 1)
在進(jìn)行如下表達(dá)式求值的時候:
val result = 3 * Fraction(4, 5)
編譯器將調(diào)用int2Fraction(3)浦妄,將整數(shù)轉(zhuǎn)換成一個Fraction對象,然后按照Fraction類的*方法定義來進(jìn)行計算见芹。

隱式轉(zhuǎn)換可以為現(xiàn)有的類庫添加功能:

我們想為java.io.File類添加一個read方法來讀取文件
在Scala中校辩,可以定義一個類型來提供read或你想要的功能:

class RichFile(val from: File) {
  def read = Source.fromFile(from.getPath).mkString
}

然后再提供一個隱式轉(zhuǎn)換來將原來的File類型轉(zhuǎn)換到新定義的類型:

implicit def file2RichFile(from: File) = new RichFile(from)

這樣就可以在File對象上調(diào)用read方法了,它被隱式轉(zhuǎn)換為一個RichFile對象辆童。

隱式轉(zhuǎn)換的規(guī)則

作用域規(guī)則

隱式轉(zhuǎn)換函數(shù)的可用位置:

  1. 位于源或目標(biāo)類型的伴生對象中的隱式函數(shù)
  1. 位于當(dāng)前作用域可以以單個標(biāo)識符指代的隱式函數(shù)

假如隱式函數(shù)放在了Conversions對象中,而這個對象位于com.xxx.yyy包惠赫,那么引入語句應(yīng)該是:import com.xxx.yyy.Conversions._把鉴。

無歧義規(guī)則

隱式轉(zhuǎn)換的應(yīng)用場景:

  • 當(dāng)表達(dá)式的類型與預(yù)期的類型不同時:
    比如sqrt(Fraction(1, 4))中,sqrt期望一個Double的參數(shù)儿咱,編譯器會調(diào)用類似fraction2Double的隱式函數(shù)來將Fraction對象轉(zhuǎn)換為Double對象庭砍。
  • 當(dāng)對象訪問一個不存在的成員時:
    比如new File("README").read中,F(xiàn)ile沒有read方法混埠,編譯器會調(diào)用file2RichFile怠缸,然后調(diào)用RichFile中定義的read方法。
  • 當(dāng)對象調(diào)用某個方法钳宪,而該方法的參數(shù)聲明與傳入?yún)?shù)不匹配時:
    比如3 * Fraction(4, 5)中揭北,Int類的*方法不接收Fraction作為參數(shù),編譯器會調(diào)用int2Fraction進(jìn)行隱式轉(zhuǎn)換吏颖。

編譯器不會使用隱式轉(zhuǎn)換的情況:

  • 如果代碼能夠不適用隱式轉(zhuǎn)換的前提下通過編譯搔体,則不會使用隱式轉(zhuǎn)換。
  • 編譯器不會嘗試同時執(zhí)行多個轉(zhuǎn)換半醉,所以隱式轉(zhuǎn)換是單一調(diào)用的疚俱。
  • 存在二義性的轉(zhuǎn)換是錯誤的,編譯器將會報錯缩多。

隱式參數(shù)

函數(shù)或方法可以帶有一個標(biāo)記為implicit的參數(shù)列表呆奕。該情況下,編譯器會查找缺省值衬吆,提供給該函數(shù)或方法梁钾。
比如:

case class Delimiters(left: String, right: String)

def quote(what: String)(implicit delims: Delimiters) =
  delims.left + what + delims.right

implicit val quoteDelimiters = Delimiters("<<", ">>")

當(dāng)我們調(diào)用quote("Scala Programming")時,編譯器會查找一個類型為Delimiters的隱式值逊抡,輸出<<Scala Programming>>陈轿。

編譯器的查找位置:

  • 當(dāng)前作用域所有可用單個標(biāo)識符指代的滿足類型要求的val和def
  • 與所要求類型相關(guān)聯(lián)的類型的繁盛對象。相關(guān)聯(lián)的類型包括所要求類型本身,以及它的類型參數(shù)麦射。

利用隱式參數(shù)進(jìn)行隱式轉(zhuǎn)換

我們提供一個泛型函數(shù)來得到相對小的值:
def smaller[T](a: T, b: T) = if (a < b) a else b
這里由于我們并不知道a和b的類型是否有<操作符蛾娶,所以編譯器不會通過。
解決辦法是添加一個隱式參數(shù)order來指代一個轉(zhuǎn)換函數(shù):

def smaller(a: T, b: T)(implicit order: T => Ordered[T])
  = if(order(a) < b) a else b

由于Ordered[T]特質(zhì)中有一個接受T作為參數(shù)的<方法潜秋,所以編譯器將在編譯時知道T蛔琅,并且從而判決是否T => Ordered[T]類型的隱式定義存在于作用域中。
這樣峻呛,才可以調(diào)用smaller(40, 2)或者smaller("AA", "BB")罗售。
注意,order是一個帶有單個參數(shù)的函數(shù)钩述,被打上了implicit標(biāo)簽寨躁,所以它不僅是一個隱式參數(shù),也是一個隱式轉(zhuǎn)換牙勘。那么职恳,我們可以在函數(shù)體重省略order的顯示調(diào)用。

def smaller[T](a: T, b: T)(implicit order: T => Ordered[T])
  = if (a < b) a else b

因為a沒有帶<的方法方面,那么會調(diào)用order(a)進(jìn)行轉(zhuǎn)換放钦。

轉(zhuǎn)載請注明作者Jason Ding及其出處
jasonding.top
Github博客主頁(http://blog.jasonding.top/)
CSDN博客(http://blog.csdn.net/jasonding1354)
簡書主頁(http://www.reibang.com/users/2bd9b48f6ea8/latest_articles)
Google搜索jasonding1354進(jìn)入我的博客主頁

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恭金,隨后出現(xiàn)的幾起案子操禀,更是在濱河造成了極大的恐慌,老刑警劉巖横腿,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颓屑,死亡現(xiàn)場離奇詭異,居然都是意外死亡耿焊,警方通過查閱死者的電腦和手機(jī)邢锯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搀别,“玉大人丹擎,你說我怎么就攤上這事⌒福” “怎么了蒂培?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長榜苫。 經(jīng)常有香客問我护戳,道長,這世上最難降的妖魔是什么垂睬? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任媳荒,我火速辦了婚禮抗悍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钳枕。我一直安慰自己缴渊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布鱼炒。 她就那樣靜靜地躺著衔沼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昔瞧。 梳的紋絲不亂的頭發(fā)上指蚁,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天,我揣著相機(jī)與錄音自晰,去河邊找鬼凝化。 笑死,一個胖子當(dāng)著我的面吹牛酬荞,可吹牛的內(nèi)容都是我干的搓劫。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼袜蚕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了绢涡?” 一聲冷哼從身側(cè)響起牲剃,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雄可,沒想到半個月后凿傅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡数苫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年聪舒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虐急。...
    茶點(diǎn)故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡箱残,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出止吁,到底是詐尸還是另有隱情被辑,我是刑警寧澤,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布敬惦,位于F島的核電站盼理,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏俄删。R本人自食惡果不足惜宏怔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一奏路、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧臊诊,春花似錦鸽粉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壶硅,卻和暖如春威兜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背庐椒。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工椒舵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人约谈。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓笔宿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親棱诱。 傳聞我的和親對象是個殘疾皇子泼橘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評論 2 350

推薦閱讀更多精彩內(nèi)容