Scala入门到精通——第十九节 隐式转换与隐式参数(二)
本節(jié)主要內(nèi)容
1. 隱式參數(shù)中的隱式轉(zhuǎn)換
前一講中,我們提到函數(shù)中如果存在隱式參數(shù),在使用該函數(shù)的時(shí)候如果不給定對(duì)應(yīng)的參數(shù),則編譯器會(huì)自動(dòng)幫我們搜索相應(yīng)的隱式值,并將該隱式值作為函數(shù)的參數(shù),這里面其實(shí)沒有涉及到隱式轉(zhuǎn)換,本節(jié)將演示如何利用隱式參數(shù)進(jìn)行隱式轉(zhuǎn)換,下面的代碼給定的是一個(gè)普通的比較函數(shù):
object ImplicitParameter extends App { //下面的代碼不能編譯通過 //這里面泛型T沒有具體指定,它不能直接使用 //<符號(hào)進(jìn)行比較def compare[T](first:T,second:T)={if (first < second) first else second} }上面的代碼要想使其編譯通過,可以前類型變量界定和視圖界定指定其上界為Ordered[T],例如:
object ImplicitParameter extends App {//指定T的上界為Ordered[T],所有混入了特質(zhì)Ordered//的類都可以直接的使用<比較符號(hào)進(jìn)行比較def compare[T<:Ordered[T]](first:T,second:T)={if (first < second) first else second} }這是一種解決方案,我們還有一種解決方案就是通過隱式參數(shù)的隱式轉(zhuǎn)換來實(shí)現(xiàn),代碼如下:
object ImplicitParameter extends App { //下面代碼中的(implicit order:T=>Ordered[T]) //給函數(shù)compare指定了一個(gè)隱式參數(shù) //該隱式參數(shù)是一個(gè)隱式轉(zhuǎn)換def compare[T](first:T,second:T)(implicit order:T=>Ordered[T])={if (first > second) first else second}println(compare("A","B")) }2. 函數(shù)中隱式參數(shù)使用概要
要點(diǎn)1:在定義函數(shù)時(shí),如果函數(shù)沒有柯里化,implicit關(guān)鍵字會(huì)作用于所有參數(shù),例如:
//implicit關(guān)鍵字在下面的函數(shù)中只能出現(xiàn)一次 //它作用于兩個(gè)參數(shù)x,y,也即x,y都是隱式參數(shù) def sum(implicit x: Int, y: Int) = x + y //下面的函數(shù)不合法,函數(shù)如果沒有柯里化,不能期望 //implicit關(guān)鍵字會(huì)作用于其中一個(gè)參數(shù) //def sum(x: Int, implicit y: Int) = x + y //def sum(implicit x: Int, implicit y: Int) = x + y另外,值得注意的是,def maxFunc(implicit x: Int, y: Int) = x + y 在使用時(shí),也只能指定一個(gè)隱式值,即指定的隱式值分別會(huì)對(duì)應(yīng)函數(shù)中的參數(shù)(這里是x,y),代碼如下:
def sum(implicit x: Int, y: Int) = x + y //只能指定一個(gè)隱式值 //例如下面下定義的x會(huì)自動(dòng)對(duì)應(yīng)maxFunc中的 //參數(shù)x,y即x=3,y=3,從而得到的結(jié)果是6implicit val x:Int=3 //不能定義兩個(gè)隱式值 //implicit val y:Int=4println(sum)要點(diǎn)2:要想使用implicit只作用于某個(gè)函數(shù)參數(shù),則需要將函數(shù)進(jìn)行柯里化,如:
def sum(x: Int)(implicit y:Int)=x+y值得注意的是,下面這種兩種帶隱式參數(shù)的函數(shù)也是不合法的
def sum(x: Int)(implicit y:Int)(d:Int)=x+y+d def sum(x: Int)(implicit y:Int)(implicit d:Int)=x+y+d要點(diǎn)3: 匿名函數(shù)不能使用隱式參數(shù),例如:
val sum2=(implicit x:Int)=>x+1要點(diǎn)4: 如何函數(shù)帶有隱式參數(shù),則不能使用其偏函數(shù),例如:
def sum(x: Int)(implicit y:Int)=x+y //不能定義sum的偏函數(shù),因?yàn)樗鼛в须[式參數(shù) //could not find implicit value for //parameter y: Int //not enough arguments for method sum: // (implicit y: Int)Int. Unspecified value parameter y.def sum2=sum _3. 隱式轉(zhuǎn)換問題梳理
1 多次隱式轉(zhuǎn)換問題 
 在上一講中我們提到,隱式轉(zhuǎn)換從源類型到目標(biāo)類型不會(huì)多次進(jìn)行,也即源類型到目標(biāo)類型的轉(zhuǎn)換只會(huì)進(jìn)行一次
- 1
注意這里指的是源類型到目標(biāo)類型的轉(zhuǎn)換只會(huì)進(jìn)行一次,并不是說不存在多次隱式轉(zhuǎn)換,在一般的方法調(diào)用過程中可能會(huì)出現(xiàn)多次隱式轉(zhuǎn)換,例如:
class ClassA {override def toString() = "This is Class A" } class ClassB {override def toString() = "This is Class B" } class ClassC {override def toString() = "This is ClassC"def printC(c: ClassC) = println(c) } class ClassDobject ImplicitWhole extends App {implicit def B2C(b: ClassB) = {println("B2C")new ClassC}implicit def D2C(d: ClassD) = {println("D2C")new ClassC}//下面的代碼會(huì)進(jìn)行兩次隱式轉(zhuǎn)換//因?yàn)镃lassD中并沒有printC方法//因?yàn)樗鼤?huì)隱式轉(zhuǎn)換為ClassC(這是第一次,D2C)//然后調(diào)用printC方法//但是printC方法只接受ClassC類型的參數(shù)//然而傳入的參數(shù)類型是ClassB//類型不匹配,從而又發(fā)生了一次隱式轉(zhuǎn)地?fù)Q(這是第二次,B2C)//從而最終實(shí)現(xiàn)了方法的調(diào)用new ClassD().printC(new ClassB) }還有一種情況也會(huì)發(fā)生多次隱式轉(zhuǎn)換,如果給函數(shù)定義了隱式參數(shù),在實(shí)際執(zhí)行過程中可能會(huì)發(fā)生多次隱式轉(zhuǎn)換,代碼如下:
object Main extends App {class PrintOps() {def print(implicit i: Int) = println(i);}implicit def str2PrintOps(s: String) = {println("str2PrintOps")new PrintOps}implicit def str2int(implicit s: String): Int = {println("str2int")Integer.parseInt(s)}implicit def getString = {println("getString")"123"}//下面的代碼會(huì)發(fā)生三次隱式轉(zhuǎn)換//首先編譯器發(fā)現(xiàn)String類型是沒有print方法的//嘗試隱式轉(zhuǎn)換,利用str2PrintOps方法將String//轉(zhuǎn)換成PrintOps(第一次)//然后調(diào)用print方法,但print方法接受整型的隱式參數(shù)//此時(shí)編譯器會(huì)搜索隱式值,但程序里面沒有給定,此時(shí)//編譯器會(huì)嘗試調(diào)用 str2int方法進(jìn)行隱式轉(zhuǎn)換,但該方法//又接受一個(gè)implicit String類型參數(shù),編譯器又會(huì)嘗試//查找一個(gè)對(duì)應(yīng)的隱式值,此時(shí)又沒有,因此編譯器會(huì)嘗試調(diào)用//getString方法對(duì)應(yīng)的字符串(這是第二次隱式轉(zhuǎn)換,//獲取一個(gè)字符串,從無到有的過程)//得到該字符串后,再調(diào)用str2int方法將String類型字符串//轉(zhuǎn)換成Int類型(這是第三次隱式轉(zhuǎn)換)"a".print }2 要不要用隱式轉(zhuǎn)換的問題
從上述代碼中可以看到,隱式轉(zhuǎn)換功能很強(qiáng)大,但同時(shí)也帶來了程序復(fù)雜性性問題,在一個(gè)程序中如果大量運(yùn)用隱式轉(zhuǎn)換,特別是涉及到多次隱式轉(zhuǎn)換時(shí),會(huì)使代碼理解起來變得比較困難,那到底要不要用隱式轉(zhuǎn)換呢?下面給出我自己開發(fā)實(shí)踐中的部分總結(jié),供大家參考: 
 1 即使你能輕松駕馭Scala語言中的隱式轉(zhuǎn)換,能不用隱式轉(zhuǎn)換就盡量不用 
 2 如果一定要用,在涉及多次隱式轉(zhuǎn)換時(shí),必須要說服自己這樣做的合理性 
 3 如果只是炫耀自己的scala語言能力,請(qǐng)大膽使用
總結(jié)
以上是生活随笔為你收集整理的Scala入门到精通——第十九节 隐式转换与隐式参数(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Scala入门到精通——第十八节 隐式转
- 下一篇: geometry-api-java 学
