请考虑以下示例:
case class C[T](x:T) {
def f(t:T) = println(t)
type ValueType = T
}
val list = List(1 -> C(2), "hello" -> C("goodbye"))
for ((a,b) <- list) {
b.f(a)
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我知道(运行时保证)类型a
将是一些T
,b
并将具有C[T]
相同的类型T
.当然,编译器无法知道,因此我们得到了输入错误b.f(a)
.
要告诉编译器这个调用没问题,我们需要做一个类型转换b.f(a.asInstanceOf[T])
.不幸的是,T
这里不得而知.所以我的问题是:如何重写b.f(a)
以使这些代码编译?
我正在寻找一个不涉及复杂结构的解决方案(以保持代码可读),并且在我们不应该依赖代码擦除来使其工作的意义上是"干净的"(参见下面的第一种方法).
我有一些工作方法,但我发现它们由于各种原因而不能令人满意.
b.asInstanceOf[C[Any]].f(a)
Run Code Online (Sandbox Code Playgroud)
这是有效的,并且具有合理的可读性,但它基于"谎言".b
不是类型C[Any]
,我们没有得到运行时错误的唯一原因是因为我们依赖于JVM(类型擦除)的限制.我认为只有x.asInstanceOf[X]
当我们知道它x
真的是类型时才使用它是好的风格X
.
b.f(a.asInstanceOf[b.ValueType])
Run Code Online (Sandbox Code Playgroud)
这应该根据我对类型系统的理解而有效.我已将该成员添加ValueType
到类C
中,以便能够显式引用type参数T
.但是,在这种方法中,我们得到一个神秘的错误消息:
Error:(9, 22) type mismatch;
found : b.ValueType
(which expands to) _1
required: _1
b.f(a.asInstanceOf[b.ValueType])
^
Run Code Online (Sandbox Code Playgroud)
为什么?它似乎抱怨我们期待类型_1
但得到类型_1
!(但即使这种方法有效,它也仅限于我们有可能添加成员的ValueType
情况C
.如果C
是某些现有的库类,我们也不能这样做.)
for ((a,b) <- list.asInstanceOf[List[(T,C[T]) forSome {type T}]]) {
b.f(a)
}
Run Code Online (Sandbox Code Playgroud)
这个工作,并且在语义上是正确的(即,我们在调用时不"撒谎" asInstanceOf
).限制是这有点难以理解.此外,它有点特定于当前情况:如果a,b
不是来自相同的迭代器,那么我们在哪里可以应用此类型转换?(此代码还具有对Intelli/J IDEA 2016.2过于复杂的副作用,它在编辑器中将其强调为错误.)
val (a2,b2) = (a,b).asInstanceOf[(T,C[T]) forSome {type T}]
b2.f(a2)
Run Code Online (Sandbox Code Playgroud)
我本来期望这个可以工作,因为a2,b2
现在应该有类型T
和C[T]
相同的存在主义T
.但是我们得到一个编译错误:
Error:(10, 9) type mismatch;
found : a2.type (with underlying type Any)
required: T
b2.f(a2)
^
Run Code Online (Sandbox Code Playgroud)
为什么?(除此之外,由于一对的创建和破坏,该方法的缺点是会产生运行时成本(我认为).)
b match {
case b : C[t] => b.f(a.asInstanceOf[t])
}
Run Code Online (Sandbox Code Playgroud)
这有效.但是使用匹配来包含代码会使代码的可读性降低.(而且它对于Intelli/J来说也太复杂了.)
最干净的解决方案是IMO,它是您在类型捕获模式匹配时找到的解决方案.通过将模式直接集成到您的理解中,您可以使其简洁,并且希望可读,如下所示:
for ((a, b: C[t]) <- list) {
b.f(a.asInstanceOf[t])
}
Run Code Online (Sandbox Code Playgroud)
小提琴:http://www.scala-js-fiddle.com/gist/b9030033133ee94e8c18ad772f3461a0
如果您还没有理解,不幸的是相应的模式分配不起作用:
val (c, d: C[t]) = (a, b)
d.f(c.asInstanceOf[t])
Run Code Online (Sandbox Code Playgroud)
那是因为t
在第二行不再是范围了.在这种情况下,您必须使用完整模式匹配.
归档时间: |
|
查看次数: |
308 次 |
最近记录: |