2013-03-06 73 views
1

我有一種方法來添加不同類型的元組到列表中,第一個元組元素始終是一個Int。我需要做一個「大於」的比較,但這是不允許的任何類型。有人能告訴我如何在下面達到預期效果嗎?檢查大於通用元組元素

感謝 德

private def add(list: List[Product], item: Product): List[Product] = { 
    if(list.isEmpty || list.head.productElement(0) > item.productElement(0)) item :: list 
    else add(list.tail, item) 
} 
+0

你不能讓類型更具體?所有長度相同的元組,可能是'(Int,Any,Any,...)'? – ziggystar 2013-03-06 14:30:41

+0

這就是HList比元組更容易處理的問題。我建議尋找使用,而不是。 – 2013-03-07 10:17:58

回答

0

如果你願意訴諸反射,你可以使用標稱和結構類型的混合物:

import scala.language.reflectiveCalls 

// A structural type exploiting the fact that all tuples have a _1 field 
type IntComponent = { val _1: Int } 

def add(list: List[Product with IntComponent], item: Product with IntComponent): List[Product with IntComponent] = { 
    if(list.isEmpty || list.head._1 > item._1) item :: list 
    else add(list.tail, item) 
} 

組合Product with IntComponent並非絕對必要,IntComponent就足夠了。但是,這種組合使您的安全性更高一些,並且允許您使用Product聲明的字段和方法(如果需要)。

這給了你不少的靜態類型安全的:

add(Nil, (1, "foo", null)) // ok 

add(Nil, ("foo", 0)) // error 
    // error: type mismatch; 
    // found : String("foo") 
    // required: Int 

add(List[Product with IntComponent](Tuple1(1), Tuple2(-1, true)), (0, "yes")) 
    // Explicit type annotation required, error otherwise 
    //  found : List[Product with Serializable] 
    //  required: List[Product with this.IntComponent] 

這種方法的明顯缺點是,你可以在一個Product with IntComponent任何對象潛行,例如

case class FakeTupleA(_1: Int) 

add(Nil, FakeTupleA(99)) // ok 

如果沒有Product要求,以下內容也可以使用:

add(Nil, new FakeTupleB(99)) 
    // error: type mismatch; 
    // found : this.FakeTupleB 
    // required: Product with this.IntComponent 
+0

給了它一些想法後,它不足以比較兩個對象的哈希碼?由於數值的散列碼始終是數值本身? – user79074 2013-03-06 15:27:27

+0

@ user79074嗯,也許吧。您也可以將'productElement(0)'強制轉換爲'Int',然後進行比較。但是,這兩種方法都不會給你任何靜態類型的安全。 – 2013-03-06 15:37:45

1

如果因爲Producer具有可變元數據而無法採用ziggystar的建議,則可以通過重構避免複雜且潛在的可讀性較低的方法來獲得所需的效果。例如:

case class Item(i: Int, item: Product) 

def add(list: List[Item], item: Item): List[Item] = { 
    if (list.isEmpty || list.head.i > item.i) item :: list 
    else add(list.tail, item) 
} 

其中,使用時,看起來是這樣的:

add(Nil, Item(1, (1, "b"))) // List(Item(1,(1,b))) 
add(List(Item(1, (1, "a"))), Item(2, (1, "b"))) // List(Item(2,(1,b))) 
add(List(Item(2, (1, "a"))), Item(1, (1, "b"))) // List(Item(1,(1,b)), Item(2,(1,a))