我有两个班,Holders(目前缺少一个更好的名字)和Holder。 Holder必须通过Holders接口,Holders具有任何类型的Holder阵列。 因此,它必须采取任何类型。我想让setValue做类型检查Any输入确实是T类型。 我已经阅读了一些关于使用清单的内容,但是我有些迷失了。有什么办法可以做我想要的吗?
class Holders {
var values = Array[Any]()
var _holders = Array[Holder[_]]()
def setData(index: Int, newValue: Any) {
values(index) = newValue
_holders(index).setValue(newValue)
}
}
class Holder[T](someData: String, initValue: T) {
private var value : T = initValue
def getValue : T = value
def setValue(newValue: Any)(implicit m: Manifest[T]) = {
if (newValue.isInstanceOf[T])
value = newValue.asInstanceOf[T]
}
}
答案 0 :(得分:2)
你可以。
注意:Manifest
已弃用,已替换为TypeTag
和ClassTag
,但这不会影响此答案的其余部分
通常在需要Manifest / TypeTag时,您确切地知道在编译时发生了什么,但是希望将这些信息保存到运行时。在这种情况下,您还必须处理这样一个事实:即使在编译时,_holders(index)
也无法告诉您它返回的是什么类型的Holder
。
根据_holders
的构建方式,可以将其替换为无形库中的Heterogeneous Map,这样就可以完全满足您的需求。< / p>
否则,您有正确的想法,在运行时测试类型。诀窍是使用TypeTag
捕获持有者的基础类型和新值的类型。
请注意,必须在所有嵌套方法上指定TypeTag
上下文绑定,以便可以在隐式范围内向下传递调用堆栈。 TypeTag
的存在是允许typeOf
继续工作的原因。
import scala.reflect.runtime.universe._ //for TypeTag
class Holders {
var values = Array[Any]()
var _holders = Array[Holder[_]]()
def setData[V: TypeTag](index: Int, newValue: V): Unit = {
values(index) = newValue
_holders(index).setValue(newValue)
}
}
class Holder[T: TypeTag](someData: String, initValue: T) {
private var value: T = initValue
def getValue: T = value
def setValue[V: TypeTag](newValue: V): Unit =
if(typeOf[V] <:< typeOf[T]) {
value = newValue.asInstanceOf[T]
}
或使用Manifest
class Holder[T: Manifest](someData: String, initValue: T) {
private var value: T = initValue
def getValue: T = value
def setValue[V: Manifest](newValue: V): Unit =
if(manifest[V] <:< manifest[T]) {
value = newValue.asInstanceOf[T]
}
我强烈建议您支持TypeTag
!
答案 1 :(得分:2)
类型擦除使得这种事情......很难。简而言之,一旦编译了代码,所有类型参数都将替换为Any
。要了解其含义,请考虑以下示例:
trait Foo[T] { def isT(a: Any): Boolean = a.isInstanceOf[T] }
object Bar extends Foo[String]
Bar.isT("foo") // true
Bar.isT(42) // also true, as Int <: Any
使用适当的选项编译时会产生警告。
在这种情况下,您有两种选择;你可以比较TypeTag
,在这种情况下你希望提供的类型参数足够准确(考虑提供的类型参数可以是value
的任何超类),或者你比较你的值的运行时类(在这种情况下,处理泛型类型时运气不好)。基于TypeTag
的解决方案可能如下所示:
class Holder[T : TypeTag](someData: String, initValue: T) {
private var value = initValue
def setValue[V : TypeTag](v: V): Unit = {
// Works because there are TypeTags for T and V in implicit scope
if(typeOf[V] <:< typeOf[T])
value = v.asInstanceOf[T]
}
}
现在你正在看这个并说“好吧这并不意味着作业实际上是value = v.asInstanceOf[Any]
?”答案是肯定的,value
也被删除为Any
。在v.asInstanceOf[T]
并不意味着“将v
转换为T
”的意义上,投射会 。相反,你所做的是说“噢,v
完全是T
- 诚实!”,因为编译器天真,它相信你。