2013-05-07 68 views
15

我可以將一個將隱式參數引入函數的方法嗎?部分應用具有隱式參數的函數

trait Tx 

def foo(bar: Any)(implicit tx: Tx) {} 

foo _ // error: could not find implicit value for parameter tx: Tx 

我想達到以下,最好是如果我能以某種方式使之與普通電話withSelection(deleteObjects)工作:

trait Test {  
    def atomic[A](fun: Tx => A): A 

    def selection: Iterable[Any] 

    def withSelection(fun: Iterable[Any] => Tx => Unit) { 
    val sel = selection 
    if (sel.nonEmpty) atomic { implicit tx => 
     fun(sel)(tx) 
    } 
    } 

    object deleteAction { 
    def apply() { 
     withSelection(deleteObjects) // ! 
    } 
    } 

    def deleteObjects(xs: Iterable[Any])(implicit tx: Tx): Unit 
} 

我發現this question,但它不處理就我所能看到的,從方法到功能的提升。

回答

6

含義僅適用於方法。但是你必須將一個函數傳遞給withSelection。您可以通過在功能包裝的方法得到解決:

withSelection(a => b => deleteObjects(a)(b)) 

它不可能通過直接deleteObjects因爲foo _不爲foo與定義的隱含參數列表工作。

4

據我所知,隱式解析必須發生在使用地點,並且不能被冒充。我自己的失望時刻是當我嘗試解決代碼中的'ExecutionContext'氾濫問題時。我一直在考慮

一個妥協:

type Async[A] = ExecutionContext => Future[A] 

def countFiles(root: String): Async[Int] = implicit ec => 
    // ... 

的'implicit'只能在函數中持有 - 我們必須在調用妥協:

implicit class AsyncExt[A](async: Async[A]) { 
    def invoke()(implicit ec: ExecutionContext) = async(ec) 
} 

implicit val ec = ... 
countFiles("/").invoke() 

另一種妥協 - 的一個我選擇住後悔:

class AsyncFileCounter(ec: ExecutionContext) { 
    def countFiles(root: String): Future[A] = ... 
} 

class FileCounter { 
    def async(implicit ec: ExecutionContext) = new AsyncFileCounter(ec) 
} 

這改變了從幼稚的使用(但德首創):

implicit val ec = ... 
val counter = new FileCounter 
counter.countFiles("/") // <-- nope 

以下幾點:

implicit val ec = ... 
val counter = new FileCounter 
counter.async.countFiles("/") // yep! 

根據你的情況下,這可能是可以忍受的。您可以在'def async'中添加'def transactional'。

但是,我確實感到遺憾,因爲它使繼承複雜化,並引發了一些分配開銷(儘管應該被打亂)。

最重要的是,你必須想出一個更明確的調用你的函數的零星方法 - 比起單獨的曲線來說不那麼優雅。

+2

關於你的第二種情況(即FileCounter),你不能定義一個隱式轉換隱式def counterToAsync(c:FileCounter):AsyncFileCounter = c.async',所以你可以再次'counter.countFiles(「/」) '? – 2013-06-08 10:53:36

+0

不錯!在我的情況下,隱式轉換將被包含對象上存在的類似簽名的同步方法擊敗。不過,這絕對是一個很好的模板解決方法!不過,我確實需要驗證轉義分析是否真的消除了Async對象的堆分配。 – nadavwr 2013-06-08 20:29:44

+0

我想說同步方法會有不同的簽名,因爲它們不會返回'Future [A]'而只是'A',所以編譯器可以告訴你。您應該簡單地分隔需要異步調用的範圍,並在其中導入隱式轉換。至於避免堆分配,我不能打賭... – 2013-06-08 22:13:52