2015-07-10 71 views
1

我有一些類型的集合Collection[SuperType]。存儲在這個集合中的幾個值是子類型SuperType,我希望集合只允許自己包含每個子類型的一個實例(有點像集合,但不是)。從參數到返回類型,在類型層次結構中的斯卡拉類型多態性

我試圖寫一個函數,鑑於上述亞型之一的同伴對象時,可以返回同伴對象所屬的類的第一個實例。

最初我與集嘗試作爲如下所示,但T將從類型擦除遭受的,所以模式匹配將失敗。然後我也意識到一個Set不適合這個任務,因爲我只想要集合中每個子類型的一次出現。

def get[T <: SuperType](target: T): Option[SuperType] = 
    collection.collectFirst({ 
    case target: T => target 
    }) 

我下了,目前的做法是使用地圖,其中關鍵是同伴對象和值是同伴對象的類的實例。類型層次結構如下所示。

trait SuperType 
trait SuperTypeValue 

// Pretend this has some parameters 
case class ExampleSubType extends SuperTypeValue 

case object ExampleSubType extends SuperType { 
    // value for use in later example 
    val uniqueToObjectField: String = "hello" 
} 

val collection: Map[SuperType, SuperTypeValue] = // Some new map 

def get(target: SuperType): Option[SuperTypeValue] = 
    collection.get(target) 

以上工作效果不錯。但是,我想保留用作參數的子類型的類型,並將其用作返回類型。我相信功能的簽名看起來是這樣的:

get[T <: SuperType](target: T): Option[T] 

// So I could then do something like this 
get(ExampleSubType) match { 
    case Some(exampleSubType) => exampleSubType.uniqueToObjectField 
    case _ => "nope" 
} 

這是可能的scala內嗎?如果是這樣,怎麼樣?如果不是,這是否存在於其他語言中,它叫什麼?

希望有這個問題沒有明顯的問題,但它是凌晨2點,所以我要在早晨再次檢查過的事情。

+0

你能不能簡單地重新定義equals方法返回如果兩個實例都是相同的,則返回true,然後直接使用Set? –

+0

好主意,應該有效。不知道我對劫持equals方法的感覺如何。 – Iain

回答

1

您可以使用ClassTags來避免類型擦除。除了使用伴侶的對象,可能更容易只提供明確泛型參數:

import scala.reflect._ 

trait SuperType { val x: Int } 

case class Foo(x: Int) extends SuperType 
case class Bar(x: Int) extends SuperType 

val collection = Set(Foo(1), Foo(2), Bar(3), Foo(4), Bar(5)) 
def get[T <: SuperType : ClassTag]: Option[T] = { 
    collection.collectFirst { 
     case target: T => target 
    } 
} 

然後你就可以撥打:

get[Foo] //Foo(1) 
get[Bar] //Bar(3) 
+0

謝謝,很高興我可以使用類型參數!我改變了'獲取[T <:SuperType:ClassTag]:選項[SuperType]'到'def獲得[T <:SuperType:ClassTag]:選項[T]'所以我可以訪問可能沒有定義的成員'SuperType'並且對於子類型是唯一的。 – Iain

+0

當然,這太好了!我已經更新了答案。 –

0

您正在試圖在需要鋸時使用錘子。您應該爲每種類型的字段創建一個新類。

class SomeClass{ 
a:TypeA 
b:TypeB 
c:TypeC 

// if c extends b extends a maybe you want 
// to prevent a TypeC being assigned to A I have no idea 
// you can change these implementations to get the behavior you want 
addA(a:TypeA){ this.a = a} 
addB(b:TypeB){ this.b = b} 
addC(c:TypeC){ this.c = c} 

} 

通常新手嘗試使用集合爲瘋狂的目的。僅僅因爲一個集合包含數據,並不意味着您想要保存數據的任何時候都需要它。在決定要使用什麼之前,你需要先思考你的需求是什麼,而不是其他方式,如果採取這種方法,你將在剩下的編程生涯中繼續工作。

+0

我應該在我的問題中明確說明這一點,但我無法明確地知道所有的子類型。如果某個圖書館的某個用戶想要爲自己的自定義子類型擴展超類型,該怎麼辦?所以我想用你的鋸子,但錘子對我的用例更好。 – Iain