鍍金池/ 教程/ Scala/ 隱含參數(shù)(一)
轉(zhuǎn)換被方法調(diào)用的對象
View 限定
概述
當有多個隱含轉(zhuǎn)換可以選擇時
隱含參數(shù)(二)
隱含參數(shù)(一)
使用 implicits 的一些規(guī)則
隱含類型轉(zhuǎn)換

隱含參數(shù)(一)

編譯器可以自動插入 implicit 的最后一個用法是隱含參數(shù)。 比如編譯器在需要是可以把 someCall(a)修改為 someCall(a)(b)或者 new someClass(a) 修改為 new SomeClass(a)(b),也就是說編譯器在需要的時候會自動補充缺少的參數(shù)來完成方法的調(diào)用。其中(b)為一組參數(shù),而不僅僅只最后一個參數(shù)。

這里我們給出一個簡單的例子:假定你定義了一個類 PreferredPrompt,其中定義了一個用戶選擇的命令行提示符(比如”$ “或者”> “)。

class PreferredPrompt(val preference:String)

另外又定義了一個 Greeter 對象,該對象定義了一個 greet 方法,該方法定義了兩個參數(shù),第一個參數(shù)代表用戶姓名,第二個參數(shù)類型為 P referredPrompt,代表提示符。

object Greeter{
    def greet(name:String)(implicit prompt: PreferredPrompt) {
        println("Welcome, " + name + ". The System is ready.")
        println(prompt.preference)
    }
}

第二個參數(shù)標記為 implicit,表明允許編譯器根據(jù)需要自動添加。 我們首先采用一般方法的調(diào)用方法,提供所有的參數(shù):

scala> val bobsPrompt =new PreferredPrompt("relax> ")
bobsPrompt: PreferredPrompt = PreferredPrompt@7e68a062
scala> Greeter.greet("Bob")(bobsPrompt)
Welcome, Bob. The System is ready.
relax> 

這種用法和我們不給第二個參數(shù)添加 implicit 調(diào)用時一樣的結(jié)果。前面我們提過,隱含參數(shù)的用法有點類似某些 Dependency Injection 框架。 比如我們在某些地方定義一個 PreferredPrompt 對象,而希望編譯器在需要時注入該對象,那么該如果使用呢。

首先,我們定義一個對象,然后在該對象中定義一個 PreferredPrompt 類型的隱含實例:

object JamesPrefs{
    implicit val prompt=new PreferredPrompt("Yes, master> ")
}

然后我們只提供第二個參數(shù)看看什么情況:

scala> Greeter.greet("James")
<console>:10: error: could not find implicit value for parameter prompt: PreferredPrompt
              Greeter.greet("James")
                           ^

出錯了,這是因為編譯器在當前作用域找不到 PreferredPrompt 類型的隱含變量,它定義在對象 JamesPrefs 中,因此需要使用 Import 引入:

scala> import JamesPrefs._
import JamesPrefs._
scala> Greeter.greet("James")
Welcome, James. The System is ready.
Yes, master> 

可以看到編譯器自動插入了第二個參數(shù),要注意的是,implicit 關(guān)鍵字作用到整個參數(shù)列表,我們修改一下上面的例子看看:

class PreferredPrompt(val preference:String)
class PreferredDrink(val preference:String)
object Greeter{
    def greet(name:String)(implicit prompt: PreferredPrompt, drink:PreferredDrink) {
        println("Welcome, " + name + ". The System is ready.")
        print("But while you work,")
        println("why not enjoy a cup of " + drink.preference + "?")
        println(prompt.preference)
    }
}
object JamesPrefs{
    implicit val prompt=new PreferredPrompt("Yes, master> ")
    implicit val drink=new PreferredDrink("coffee")
}
import JamesPrefs._
Greeter.greet("James")
scala> Greeter.greet("James")
Welcome, James. The System is ready.
But while you work,why not enjoy a cup of coffee?
Yes, master> 

這里有一點要注意的是,這里 implicit 參數(shù)的類型我們沒有直接使用 String 類型,事實我們可以使用 String 類型:

object Greeter{
    def greet(name:String)(implicit prompt: String) {
        println("Welcome, " + name + ". The System is ready.")
        println(prompt)
    }
}
implicit val prompt="Yes, master> "
Greeter.greet("James")
scala> Greeter.greet("James")
Welcome, James. The System is ready.
Yes, master> 

當問題是如果有多個參數(shù)都使用 implicit 類型,而類型相同,你就無法提供多個參數(shù),因此 implicit 類型的參數(shù)一般都是定義特殊的類型。