如何代理对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
看来,你想要的基本上是一个类型化的地图。很明显,你想要做的事情根本无法工作。当您致电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这种东西你可以在异质类型的集合方面做。
非常感谢您的努力。对于类型,方差,泛型等,我仍然是一个新手。我现在使用这个[解决方案](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
)
}
这使直接获取调用返回某种类型的属性。
感谢您的回答,但这不是我想要的(请参阅更新的问题)。如果我在道具中使用不同类型的属性,并且所有属性都是PropertyAbstract的子类型,该怎么办? – roelio 2012-02-02 11:43:33
对于'the_correct_type_prop',我得到'PropertyAbstract [_>:C with B 2012-02-02 11:48:30
我也认为这是正确的。但是有没有办法在'PropertyA'的'revs'数组中添加'B'类型的对象(并且在尝试添加'C'时出错)?我认为我使用的数据结构不允许这样做。 – roelio 2012-02-02 11:59:41