简体   繁体   English

如何为asInstanceOf指定链接类型

[英]How to specify linked types for asInstanceOf

The title is not too descriptive, but I'm not aware how the used pattern is properly called. 标题不太具描述性,但我不知道如何正确调用所使用的模式。 I hope all would become clear with example. 我希望所有人都能以身作则。

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

Types OneExample and TwoExample is normally recognized by each other. 通常可以相互识别类型OneExampleTwoExample The testByKnot method shows it. testByKnot方法显示它。 I can also call the use method with static parametrization by Knot . 我还可以通过Knot调用带有静态参数化的use方法。 The types would be compatible, as shown in the testByKnot method. 类型将兼容,如testByKnot方法所示。

But I need to discard type information to store data in a collection. 但是我需要丢弃类型信息以将数据存储在集合中。 eg Map[Knot[_], OneKnot[_]] . 例如Map[Knot[_], OneKnot[_]] So I need to restore types after extraction from collection using asInstanceOf . 所以我需要使用asInstanceOf从集合中提取数据后还原类型。 But I failed to specify correctly to what types the cast needed. 但是我无法正确指定所需的转换类型。

In the last two test methods I get two corresponding errors: 在最后两种测试方法中,我得到两个相应的错误:

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

How the cast should be done properly? 如何正确地进行投射?

How about using type K <: Knot[K] to glue/cast the two knots types together? 如何使用类型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])
}

You can then call one of the cast methods directly. 然后,您可以直接调用其中一种强制转换方法。

val one    = new OneExample { def use(second: TwoExample) = ??? }
val two    = new TwoExample {}
val result = testByCast(one, two)

The answer summarize approach suggested by Andy 答案总结了安迪建议的方法

You may use type parametrization but never specify the needed tag. 您可以使用类型参数化,但不要指定所需的标签。 see the sample: 查看示例:

def testByDiscard[K <: Knot[K]]( one : OneKnot[_], two : TwoKnot[_] ) =
  one.asInstanceOf[K#One].use(two.asInstanceOf[K#Two])

The mystery is that compiler managed to substitute something meaningful to the type parameters. 神秘之处在于,编译器设法将有意义的内容替换为类型参数。 The type parameter may never be specified, but this construction would still works. 类型参数可能永远不会被指定,但是这种构造仍然有效。 Anyway java gets rid of all type parameters, so no crucial information is lost. 无论如何,java摆脱了所有类型参数,因此不会丢失任何关键信息。

I was curious what is the magic type the compiler use. 我很好奇编译器使用什么魔术类型。 And add implicit type tag to get it. 并添加隐式类型标记以获取它。 It was just simple Nothing not a complicated type erasure type. 只是简单Nothing不是复杂的类型擦除类型。 Static type checker really does not complain agains the further usage: 静态类型检查器确实不再抱怨进一步的用法:

val exo : OneExample = new OneExample
val ext : TwoExample = new TwoExample
Test.testByDiscard[Nothing](exo, ext)

But fails as expected when trying to cast directly to Nothing#One or Nothing#Two . 但是尝试直接转换为Nothing#OneNothing#Two时,按预期方式失败。 It also fails when trying with calling testByKnot[Nothing] that is identical to discard case but without asInstanceOf call. 当尝试调用与废弃情况相同但没有asInstanceOf调用的testByKnot[Nothing] ,它也会失败。 It is quite amusing how the scala type manager works, but it deserves separate question. scala类型管理器的工作方式非常有趣,但是值得单独提出一个问题。

This question is closed with answer provided by Andy and detailed by me above. 这个问题已经由安迪(Andy)提供并在上面由我详细介绍了。 It just works. 它只是工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM