如何代理对hashmap的调用而不会丢失类型

问题描述:

在下面的代码中,当我直接从散列表中获得属性的正确类型(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 2012-02-02 11:48:30

+0

我也认为这是正确的。但是有没有办法在'PropertyA'的'revs'数组中添加'B'类型的对象(并且在尝试添加'C'时出错)?我认为我使用的数据结构不允许这样做。 – roelio 2012-02-02 11:59:41

看来,你想要的基本上是一个类型化的地图。很明显,你想要做的事情根本无法工作。当您致电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

的问题是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