在下面的代码中,当我从hashmap直接得到它时,我得到了正确的属性类型(PropertyA
)。
当我通过ClassAbstract
中的get方法代理此调用时类型为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)
}
我想要的结果是我可以向prop1添加B
类型的元素,但不能添加C
类型的元素
答案 0 :(得分:3)
问题是get
是在ClassAbstract中定义的,而道具是在Class中具体定义的,并且还有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
)
}
这使得直接get调用返回类型为Property的内容。
答案 1 :(得分:2)
看起来你想要的实际上是一个打字的地图。很明显,你要做的事情根本无法奏效。当您致电get
时,您会收到PropertyAbstract[X]
的未知X
(除非是A
的子类型)。你怎么能假设它需要B
s?
解决方案是让你的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 = Class@298508
scala> val proxied_prop = the_class.get("prop1")
proxied_prop: PropertyAbstract[_ <: A] = PropertyA@a269e2
scala> val direct_prop = the_class.props.get("prop1").get
direct_prop: PropertyAbstract[C with B] = PropertyA@a269e2
以下编译:
scala> proxied_prop.revs.add(new B)
res0: Boolean = true
scala> direct_prop.revs.add(new B)
res1: Boolean = true
但当然你可以放任何东西!
也许你应该看一下Miles Sabin's shapeless你可以 在非异类型集合方面做的事情。