2010-12-06 47 views
7

在Scala中,我們可以使用隱含類型類有條件地添加到方法的參數化類型依賴於該類型的參數。例如,Iterator.sum添加有效性檢查依賴於一個類型類(可選implicits)

def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus) 

必須有Numeric類型類此方法的一個實例,甚至被稱爲:

scala> List(1, 2, 3).sum 
res0: Int = 6 

scala> List("a", "b").sum 
<console>:6: error: could not find implicit value for parameter num: Numeric[java.lang.String] 
     List("a", "b").sum 
       ^

到目前爲止,一切都很好。比方說,我希望有一些集合類型,My2Col

class My2Col[A](a1 : A, a2 : A) 

但我想強制要求,如果A : Numeric製成,然後a2 > a1。然而,這是完全有效爲它與A這不是數字進行。

My2Col("a", "b") //OK 
My2Col("b", "a") //OK 
My2Col(1, 2)  //OK 
My2Col(2, 1)  //THROW IllegalArgumentException 

有沒有人有任何想法可以做到這一點?

PS。如果任何人有一個更好的問題標題任何建議,我所有的耳朵

回答

12
class My2Col[A](a1 : A, a2 : A)(implicit num: Numeric[A] = null){ 
    for{check <- Option(num); if(check.gteq(a1, a2))} 
    throw new IllegalArgumentException 
} 
3

我將通過創建2個implicits代表的要求,實現這一個是更普遍的(比,比方說,IntNumeric[T]其他所有類型) ,另一個更具體(對於IntNumeric[T])。

然後,按照隱式解析的規則,我會將更具體的一個放在Requirement類型的伴隨對象中,並且在伴隨對象的基類中放置更通用的對象。這樣我會確保編譯器首先嚐試應用更具體的。

當然,缺點是,如果用戶明確提供的隱含參數,這一機制可以規避無法做檢查。

像這樣的東西(其中Int是特定規則的類型,Foo是集合類):

package ex                           

    trait Requirement[T] {                        
    def check(a1: T, a2: T): Unit                     
    }                             

    trait BaseReq {                         
    implicit def genericReq[T] = new Requirement[T] {                
     def check(a1: T, a2: T) {println("generic")}                 
    }                            
    }                             

    object Requirement extends BaseReq {                    
    implicit object IntReq extends Requirement[Int] {                
     def check(a1: Int, a2: Int) = {                    
     println("int")                        
     if (a2 <= a1) throw new IllegalArgumentException                
     }                            
    }                            
    }                             

    class Foo[T](a1: T, a2: T)(implicit req: Requirement[T]) {               
    req.check(a1, a2)                        

    // whatever `foo` does follows                     
    }                            

    object Main {                          
    def main(args: Array[String]) {                     
     new Foo(1, 2)                         
     new Foo("S1", "S2")                       
     new Foo(2, 1)                         
    }                            
    } 
+0

我不知道如何讓富[T:要求。任何理想? – pedrofurla 2010-12-06 11:30:39

+0

嗯,我不知道,如果可以再訪問`Requirement`對象如果您使用綁定(即`美孚[T:要求]`)上下文來調用它的方法.. – axel22 2010-12-06 12:18:56