使用scala泛型和清单在类内强制转换
我有两个班,Holder(目前没有更好的名字)和Holder。 支架必须通过支架连接,支架具有任何类型的支架阵列。 因此,它必须采取任何类型。我想让setValue进行类型检查,以确保任何输入都确实是T类型。 我读过一些关于使用清单的书,但是我有点迷路了。有什么办法可以满足我的要求吗使用scala泛型和清单在类内强制转换,scala,type-erasure,erasure,Scala,Type Erasure,Erasure,我有两个班,Holder(目前没有更好的名字)和Holder。 支架必须通过支架连接,支架具有任何类型的支架阵列。 因此,它必须采取任何类型。我想让setValue进行类型检查,以确保任何输入都确实是T类型。 我读过一些关于使用清单的书,但是我有点迷路了。有什么办法可以满足我的要求吗 class Holders { var values = Array[Any]() var _holders = Array[Holder[_]]() def setData(index:
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]
}
}
你可以
注意:Manifest
已被弃用并替换为TypeTag
和ClassTag
,但这并不影响本答案的其余部分
通常,当需要清单/类型标记时,您确切地知道在编译时发生了什么,但也希望将这些信息保存到运行时。在这种情况下,您还必须处理这样一个事实,即即使在编译时,\u持有者(索引)
也不能告诉您它返回的是什么类型的持有者
根据\u支架
的构建方式,可能会将其替换为不成形库中的,这将完全满足您的需要
否则,您的想法是正确的,在运行时测试类型。诀窍是使用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]
}
不过,我强烈建议您支持TypeTag
你可以
注意:Manifest
已被弃用并替换为TypeTag
和ClassTag
,但这并不影响本答案的其余部分
通常,当需要清单/类型标记时,您确切地知道在编译时发生了什么,但也希望将这些信息保存到运行时。在这种情况下,您还必须处理这样一个事实,即即使在编译时,\u持有者(索引)
也不能告诉您它返回的是什么类型的持有者
根据\u支架
的构建方式,可能会将其替换为不成形库中的,这将完全满足您的需要
否则,您的想法是正确的,在运行时测试类型。诀窍是使用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]
}
不过,我强烈建议您支持TypeTag
类型擦除使这种事情。。。很难。简而言之,编译代码后,所有类型参数都将替换为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
现在你看到这一点并说“这不意味着赋值实际上是value=v.asInstanceOf[Any]
?”,答案是肯定的-value
也被擦除为Any
。铸造没有任何作用,从某种意义上说,v.asInstanceOf[T]
并不意味着“将v
转换为T
”。相反,你所做的是说“哦,是的,v
完全是一个T
-诚实!”,因为编译器很幼稚,它相信你。类型擦除使这种事情。。。很难。简而言之,编译代码后,所有类型参数都将替换为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
现在你看到这一点并说“这不意味着赋值实际上是value=v.asInstanceOf[Any]
?”,答案是肯定的-value
也被擦除为Any
。铸造没有任何作用,从某种意义上说,v.asInstanceOf[T]
并不意味着“将v
转换为T
”。相反,您所做的是说“哦,是的,v
完全是一个T
-诚实!”,因为编译器很幼稚,它相信您。在您的示例中,在setValue中测试T不是因为类型擦除而没有做任何事情吗?当我尝试你所拥有的东西时,我得到一个警告,由于擦除,这将不起作用,因为对于任何可能的nv
,都是真的。那么有什么方法可以让我检查我的any是否属于类型T?为什么清单不支持=:=:(正在比较清单[T]。runtimeClass==清单[V].runtimeClass等价物?您不需要这里的=:=
。我假设您希望能够将FordFiesta
放入支架[汽车]
在您的示例中,在setValue中测试t不是因为类型擦除而没有做任何事情吗?我在尝试您拥有的东西时收到一条警告,由于擦除,这将不起作用,因为案例nv:t
对于任何可能的nv
都是正确的。那么我有没有办法检查我的any是否属于类型t?为什么不显示支持=:=:(正在比较清单[T]。runtimeClass==清单[V]。runtimeClass等效物?您不希望=:=
在这里。我假设您希望能够将FordFiesta
放入支架[Car]
是否会使用=:=修复我的超类问题?是否有任何方法可以使用清单做完全相同的事情?理想情况下,我会坚持使用scala2.8我相信您应该能够使用清单代替标记来完成同样的事情,因为TypeTag
是与反射API集成的清单的演变-请参阅API文档n:“超类型问题”源于调用者可以通过“欠报告”参数类型来“撒谎”,例如setValue[Any](“foo”)
。同样值得注意的是,您得到的是d