[英]How to specify linked types for asInstanceOf
标题不太具描述性,但我不知道如何正确调用所使用的模式。 我希望所有人都能以身作则。
trait OneKnot[K <: Knot[K]] { this : K#One =>
type OK = K // for example only. To show that it is actually defined
def use(second : OK#Two)
}
trait TwoKnot[K <: Knot[K]] { this : K#Two => }
trait Knot[K <: Knot[K]] {
type One <: OneKnot[K]
type Two <: TwoKnot[K]
}
trait KnotExample extends Knot[KnotExample] {
override type One = OneExample
override type Two = TwoExample
}
trait OneExample extends OneKnot[KnotExample]
trait TwoExample extends TwoKnot[KnotExample]
object Test {
def testByName( one : OneExample, two : TwoExample ) = one.use(two)
def testByKnot[K <: Knot[K]]( one : K#One, two : K#Two ) = one.use(two)
def testByCast(knot : Knot[_], one : OneKnot[_], two : TwoKnot[_]) = one.asInstanceOf[knot.One].use(two.asInstanceOf[knot.Two])
def testByInnerCast(one : OneKnot[_], two : TwoKnot[_]) = one.use( two.asInstanceOf[one.OK#Two] )
}
通常可以相互识别类型OneExample
和TwoExample
。 testByKnot
方法显示它。 我还可以通过Knot
调用带有静态参数化的use
方法。 类型将兼容,如testByKnot
方法所示。
但是我需要丢弃类型信息以将数据存储在集合中。 例如Map[Knot[_], OneKnot[_]]
。 所以我需要使用asInstanceOf
从集合中提取数据后还原类型。 但是我无法正确指定所需的转换类型。
在最后两种测试方法中,我得到两个相应的错误:
NotSameType.scala:25: error: type mismatch;
found : knot.Two
required: _$1#Two
def testByCast(knot : Knot[_], one : OneKnot[_], two : TwoKnot[_]) = one.asInstanceOf[knot.One].use(two.asInstanceOf[knot.Two])
^
NotSameType.scala:26: error: type Two is not a member of one.OK
def testByInnerCast(one : OneKnot[_], two : TwoKnot[_]) = one.use( two.asInstanceOf[one.OK#Two] )
如何正确地进行投射?
如何使用类型K <: Knot[K]
将两种类型的结粘合/浇铸在一起?
object Test {
def testByName(one: OneExample, two: TwoExample) = one.use(two)
def testByKnot[K <: Knot[K]](one: K#One, two: K#Two) = one.use(two)
def testByCast[K <: Knot[K]](one: OneKnot[_], two: TwoKnot[_]) =
one.asInstanceOf[K#One].use(two.asInstanceOf[K#Two])
def testByInnerCast[K <: Knot[K]](one: OneKnot[_], two: TwoKnot[_]) =
one.asInstanceOf[K#One].use(two.asInstanceOf[K#One#OK#Two])
}
然后,您可以直接调用其中一种强制转换方法。
val one = new OneExample { def use(second: TwoExample) = ??? }
val two = new TwoExample {}
val result = testByCast(one, two)
答案总结了安迪建议的方法
您可以使用类型参数化,但不要指定所需的标签。 查看示例:
def testByDiscard[K <: Knot[K]]( one : OneKnot[_], two : TwoKnot[_] ) =
one.asInstanceOf[K#One].use(two.asInstanceOf[K#Two])
神秘之处在于,编译器设法将有意义的内容替换为类型参数。 类型参数可能永远不会被指定,但是这种构造仍然有效。 无论如何,java摆脱了所有类型参数,因此不会丢失任何关键信息。
我很好奇编译器使用什么魔术类型。 并添加隐式类型标记以获取它。 只是简单Nothing
不是复杂的类型擦除类型。 静态类型检查器确实不再抱怨进一步的用法:
val exo : OneExample = new OneExample
val ext : TwoExample = new TwoExample
Test.testByDiscard[Nothing](exo, ext)
但是尝试直接转换为Nothing#One
或Nothing#Two
时,按预期方式失败。 当尝试调用与废弃情况相同但没有asInstanceOf
调用的testByKnot[Nothing]
,它也会失败。 scala类型管理器的工作方式非常有趣,但是值得单独提出一个问题。
这个问题已经由安迪(Andy)提供并在上面由我详细介绍了。 它只是工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.