2011-05-11 84 views
4

我有一個類需要一個隱式參數,由內部類方法調用的函數使用。我希望能夠覆蓋該隱式參數,或者可以從源代碼中複製隱式參數。舉個例子:scala:覆蓋構造函數的隱式參數

def someMethod()(implicit p: List[Int]) { 
    // uses p 
} 

class A()(implicit x: List[Int]) { 

    implicit val other = List(3) // doesn't compile 

    def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that 
    someMethod() 
    } 
} 

我想要的行爲是的someMethod()獲取一些改變x版本,這是班上的隱含參數的隱含參數。我希望能夠對x進行變異,而無需將其傳遞給A的構造函數,或者將其重寫爲我選擇的新值。這兩種方法似乎都不起作用。也就是說,它不會複製前一種情況下的列表,並且編譯器爲後一種情況找到一個模糊的隱式值。有沒有辦法做到這一點?

我意識到我可以重新定義go()中的隱式值,但在我的情況下,這不是一個好的選擇,因爲這個類被多次子類化,我想處理基類中的這種隱式更改只要。所以它不一定需要進入構造函數,但它必須使用go()以外的方法。

+1

這看起來像你正在迅速進入不可維護代碼領域。你想要在someMethod上隱含參數,你的邏輯是什麼?爲什麼不把它作爲一個明確的參數? – 2011-05-11 10:45:41

+1

@Kevin在我的特殊情況下,有數千個像A這樣的子類以及它們構建的數千次。不必將相同的參數傳遞給每個人都很方便。你爲什麼說這是不可維護的? – 2011-05-11 20:41:26

+0

當試圖推理您的代碼時,如果您在範圍內看到特定的某種類型的隱式,那麼期望在調用堆棧中更深的相同類型的隱式將是同一實例是很自然的。如果這個假設是錯誤的,那麼對於不知道變化的人來說,這可能會使調試變得非常困難。 – 2011-05-12 11:24:50

回答

8

介紹另一個包裝類型,只是爲了消除歧義:

// badly named, choose something domain-specific 
case class ListHolder(theList: List[Int]) 

def someMethod()(implicit holder: ListHolder) { 
    val xs = holder.theList 
    // uses xs ... 
} 

class A()(implicit xs: List[Int]) { 

    implicit val other = ListHolder(42 :: xs) // compiles 

    def go() { 
    // xs is never considered for the implicit param to someMethod() 
    // because it's now the wrong type 
    } 
} 

這也使得代碼更自我記錄,因爲它變得一清二楚的是,這兩個暗示是而不是一樣。

0

此修改編譯。我改變x轉換成VAR:

class A()(implicit var x: List[Int]) { 

    def someMethod()(implicit p: List[Int]) { 
    // uses p 
    } 

    x = List(3) 

    def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that 
    someMethod() 
    } 
} 
3

如果你想有implicits漂浮不計其數不相互碰撞,你可以創建你可以標記性狀隱含使用標記的包裝類。您可以使用多種語法;這裏有一個例子:

object Example { 
    class Implication[A,B](val value: A) { 
    def apply[C](c: C) = new Implication[C,B](c) 
    } 
    object Implication { 
    def mark[B] = new Implication[Unit,B](()) 
    implicit def implication_to_value[A,B](i: Implication[A,B]) = i.value 
    } 

    trait One {} 
    trait Two {} 
    implicit val x = Implication.mark[One]("Hello") 
    implicit val y = Implication.mark[Two]("Hi") 

    def testOne(implicit s: Implication[String,One]) = println(s: String) 
    def testTwo(implicit s: Implication[String,Two]) = println(s: String) 
    def testThree(s: String) = println("String is " + s) 

    def main(args: Array[String]) { 
    testOne 
    testTwo 
    testThree(x) 
    testThree(y) 
    } 
} 

其中一期工程,你會希望:

scala> Example.main(Array()) 
Hello 
Hi 
String is Hello 
String is Hi 

因爲你必須使用一個包裝對象,它不是超級節能,但它可以是非常有效的。 (或非常混亂,給多少隱含發生。)