2012-02-02 69 views
2

在下面的代碼中,當我直接從散列表中獲得屬性的正確類型(PropertyA)時。如何代理對hashmap的調用而不會丟失類型

當我代理這個呼叫通過get方法ClassAbstract類型爲PropertyAbstract[_ <: A]

有沒有辦法來代理調用HashMap和保持正確的類型?

另一個問題是如何通過類型檢查將對象添加到revs數組?

class A 
class B extends A 
class C extends A 

abstract class PropertyAbstract[T] { 
    val revs = new java.util.ArrayList[T] 
} 

class PropertyA extends PropertyAbstract[B] 
class PropertyB extends PropertyAbstract[C] 

abstract class ClassAbstract { 
    val props: scala.collection.immutable.HashMap[String, PropertyAbstract[_ <: A]] 
    def get(prop: String) = props.get(prop).get 
} 

class Class extends ClassAbstract { 
    val props = collection.immutable.HashMap(
     "prop1" -> new PropertyA, 
     "prop2" -> new PropertyB 
) 
} 

object Test extends App { 
    val the_class = new Class 
    val proxied_prop = the_class.get("prop1") 
    val direct_prop = the_class.props.get("prop1").get 

    // wont compile (found: B  required: _$1 <: A) 
    proxied_prop.revs.add(new B) 
    // wont compile (found: B  required: C with B) 
    direct_prop.revs.add(new B) 
} 

的通緝的結果是,我可以B類型的一個元素添加到PROP1,而不是類型的元素C

+1

對於'the_correct_type_prop',我得到'PropertyAbstract [_>:C with B <:A]'。如果您查看'the_class.props'的類型,這是預期的。 – 2012-02-02 11:48:30

+0

我也認爲這是正確的。但是有沒有辦法在'PropertyA'的'revs'數組中添加'B'類型的對象(並且在嘗試添加'C'時出錯)?我認爲我使用的數據結構不允許這樣做。 – roelio 2012-02-02 11:59:41

回答

2

看來,你想要的基本上是一個類型化的地圖。很明顯,你想要做的事情根本無法工作。當您致電get時,您會收到一個PropertyAbstract[X]未知的X(除非它是A的子類型)。那麼你怎麼會認爲這需要B

的解決方案是爲您PropertyAbstract逆變但是這意味着它不能成爲可變集合以任何合理的方式(也可以是可變的,當然,但你能得到什麼出將是一個A) 。

scala> class A; class B extends A; class C extends A 
defined class A 
defined class B 
defined class C 

scala> abstract class PropertyAbstract[-T] { val revs = new java.util.ArrayList[AnyRef] } 
defined class PropertyAbstract 

scala> class PropertyA extends PropertyAbstract[B]; class PropertyB extends PropertyAbstract[C] 
defined class PropertyA 
defined class PropertyB 

scala> abstract class ClassAbstract { 
    | val props: Map[String, PropertyAbstract[_ <: A]] 
    | def get(prop: String) = (props get prop).get 
    | } 
defined class ClassAbstract 

scala> class Class extends ClassAbstract { val props = Map("prop1" -> new PropertyA, "prop2" -> new PropertyB) } 
defined class Class 

scala> val the_class = new Class 
the_class: Class = [email protected] 

scala> val proxied_prop = the_class.get("prop1") 
proxied_prop: PropertyAbstract[_ <: A] = [email protected] 

scala> val direct_prop = the_class.props.get("prop1").get 
direct_prop: PropertyAbstract[C with B] = [email protected] 

以下編譯:

scala> proxied_prop.revs.add(new B) 
res0: Boolean = true 

scala> direct_prop.revs.add(new B) 
res1: Boolean = true 

不過,當然,你可以把任何東西在那裏!

也許你應該看看Miles Sabin's shapeless這種東西你可以在異質類型的集合方面做。

+0

非常感謝您的努力。對於類型,方差,泛型等,我仍然是一個新手。我現在使用這個[解決方案](http://stackoverflow.com/a/4310959/730277),其中hashmap的鍵包含價值。我也查找了HList,但我必須弄清楚這是否也可以用作散列表。 – roelio 2012-02-02 16:09:55

3

的問題是get在ClassAbstract定義和道具在具體定義類,並進一步類型細化,ClassAbstract無法訪問。我們需要提供一種方式將這些額外的類型信息從Class傳回ClassAbstract。以下是這樣做的一種方法。

abstract class ClassAbstract[P <: PropertyAbstract[_ <: A]] { 
    val props: scala.collection.immutable.HashMap[String,P] 
    def get(prop: String) = props.get(prop) 
} 

class Class extends ClassAbstract[Property] { 
    val props = collection.immutable.HashMap(
     "prop" -> new Property 
) 
} 

這使直接獲取調用返回某種類型的屬性。

+0

感謝您的回答,但這不是我想要的(請參閱更新的問題)。如果我在道具中使用不同類型的屬性,並且所有屬性都是PropertyAbstract的子類型,該怎麼辦? – roelio 2012-02-02 11:43:33

相關問題