如何为asInstanceOf指定链接类型

时间:2015-07-26 05:03:57

标签: scala types casting

标题不太具描述性,但我不知道如何正确调用所使用的模式。我希望所有人都能通过榜样变得清晰。

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] )
}

类型OneExampleTwoExample通常互相识别。 testByKnot方法显示了它。我还可以通过use使用静态参数化调用Knot方法。这些类型是兼容的,如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] )

演员表应如何正确完成?

2 个答案:

答案 0 :(得分:1)

如何使用类型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)

答案 1 :(得分:0)

答案总结了Andy

建议的方法

您可以使用类型参数化,但从不指定所需的标记。看样品:

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#OneNothing#Two时失败了。尝试调用testByKnot[Nothing]时,它与discard case相同但没有asInstanceOf调用也会失败。 scala类型管理器的工作原理非常有趣,但它值得单独提问。

这个问题以Andy提供的答案结束,并在上面详述。它只是有效。