在Scala中的泛型类型上使用asInstanceOf
比如说,我有一门课是这样的:在Scala中的泛型类型上使用asInstanceOf,scala,shapeless,Scala,Shapeless,比如说,我有一门课是这样的: class Funky[A, B](val foo: A, val bar: B) { override def toString: String = s"Funky($foo, $bar)" } def cast(t: Any): Option[Funky[A, B]] = { if (t == null) None else if (t.isInstanceOf[Funky[_, _]]) { val o = t.asInstanceOf[
class Funky[A, B](val foo: A, val bar: B) {
override def toString: String = s"Funky($foo, $bar)"
}
def cast(t: Any): Option[Funky[A, B]] = {
if (t == null) None
else if (t.isInstanceOf[Funky[_, _]]) {
val o = t.asInstanceOf[Funky[_, _]]
for {
_ <- typA.cast(o.foo)
_ <- typB.cast(o.bar)
} yield o.asInstanceOf[Funky[A, B]]
} else None
}
使用如下所示的某种方法:
class Funky[A, B](val foo: A, val bar: B) {
override def toString: String = s"Funky($foo, $bar)"
}
def cast(t: Any): Option[Funky[A, B]] = {
if (t == null) None
else if (t.isInstanceOf[Funky[_, _]]) {
val o = t.asInstanceOf[Funky[_, _]]
for {
_ <- typA.cast(o.foo)
_ <- typB.cast(o.bar)
} yield o.asInstanceOf[Funky[A, B]]
} else None
}
def cast(t:Any):选项[Funky[A,B]={
如果(t==null)无
else if(t.isInstanceOf[Funky[,]]{
val o=t.asInstanceOf[Funky[,]]
为了{
_您可以检查元素是否为特定类型,例如:
Funky(1, 2).foo.isInstanceOf[String] // false
Funky(1, 2).foo.isInstanceOf[Int] // true
但是,如果您尝试检查泛型类型,它将不起作用。例如:
def check[A](x: Any) = x.isInstanceOf[A]
check[String](1) // true
check[String](Funky(1, 2).foo) // true
编译器会给您一条警告消息,解释错误:
抽象类型A未选中,因为它是通过擦除消除的
但是,您展示的代码似乎通过其他方法解决了这个问题:
_ <- typA.cast(o.foo)
_ <- typB.cast(o.bar)
\up>让我们把它拆开
假设您以某种方式获得实例typA:Typable[A]
和typB:Typable[B]
,这样typA
就有了一个方法
def cast(a: Any): Option[A] = ...
同样,对于typB
,如果参数确实是A
类型,则cast
方法将返回Some[A]
,否则返回None
。显然,可以为基本类型Int
和String
构造这些实例(它们已经由库提供)
现在,您需要使用typA
和typB
为Funky[A,B]
实现cast
null
检查应该是清除的,您可以对任何东西执行它。但是接下来是第一个isInstanceOf
:
else if (t.isInstanceOf[Funky[_, _]]) {
请注意,Funky
的类型参数已替换为下划线。这是因为Funky
的泛型参数已被删除,并且在运行时不可用。但是,我们仍然可以区分Funky[\uu,\u]
和,例如,Map[\uu]
,因为参数化类型本身被保留,即使参数被删除。此外,isInstanceOf
甚至可以区分TreeMap
和HashMap
,即使这两个实例都有编译时类型Map
:运行时类型可用,它只是至少,我们被遗忘了
类似地,一旦您知道t
属于Funky
类型,就可以将其转换为
时髦的
val o = t.asInstanceOf[Funky[_, _]]
用存在类型替换泛型参数。这意味着:您只知道有一些类型X
和Y
,因此o
属于Funky[X,Y]类型
,但您不知道那些X
和Y
是什么。然而,现在您至少知道o
有方法foo
和bar
(即使您不知道它们的返回类型是什么)
但是现在您可以将o.foo
和o.bar
输入typA.cast
和typeB.cast
。一元绑定左侧的下划线意味着您放弃类型A
和B
的实例,它们以Some
的形式返回。您只关心这个both强制转换不返回None
:
for {
_ <- typA.cast(o.foo)
_ <- typB.cast(o.bar)
} yield /* ... */
您可能想知道“这怎么可能,我们对运行时的A
和B
一无所知!”,但这是可以的,因为这个asInstanceOf
只是为了满足编译器的类型检查阶段。它在运行时不能做任何事情,因为它只能检查Funky
部分,而不能检查已删除的参数A
和B
以下是对这一现象的简短说明:
val m: Map[Long, Double] = Map(2L -> 100d)
val what = m.asInstanceOf[Map[Int, String]]
println("It compiles, and the program does not throw any exceptions!")
只需将其保存为脚本并将其提供给scala
解释器。它将编译并运行,不会产生任何抱怨,因为asInstanceOf
对Map
之外的任何内容都是盲的。因此,第二个asInstanceOf
只是为了说服类型检查器返回的值确实是Funky类型[A,B]
,程序员有责任不做出任何无意义的声明
总而言之:isInstanceOf
是在运行时执行某些操作的东西(它检查实例是否符合某个具体类型,并返回运行时值true
-false
)。asInstanceOf
有两个不同的函数。第一个函数(强制转换到具体类Funky[\uu,\u]
)在运行时有副作用(强制转换可能会失败并引发异常)。第二个(asInstanceOf[Funky[a,B]]]
)仅用于满足编译时的类型检查阶段
希望这能有所帮助。你看过asInstanceOf
操作符的源代码了吗?@BobDalgleish至少在这里:你看不到太多。大多数“有趣”的方法都是作为sys.error(“”)实现的
。该类非常基本,字节码不是从任何源代码编译的,而是由编译器直接生成的。源代码主要是用来生成ScalaDoc的。我不明白你想说什么!我想知道编译器如何解释泛型asInstanceOf?我给出了一个cast方法,它是missing!好的,我试着编辑并回答了更多的问题。感谢您包含了更多的方法,但它仍然调用了一些typA.cast
方法crucial@JoeK我的猜测是,这些东西都是可打字的typeclass的实例。。。