下面是一个简单的例子:
object MatchErasedType {
trait Supe {
self: Singleton =>
type T1
lazy val default: T1
def process(v: Any): T1 = {
v match {
case vv: T1 => vv
case _ => default
}
}
}
}
它将抛出编译器警告:
MatchErasedType.scala:13:14: the type test for Supe.this.T1 cannot be checked at runtime
这个例子很有趣,因为Supe
的任何示例都可以保证是Singleton
,所以process
的延迟物化不会有任何擦除,因此,这个问题实际上包含两种不同的情况:
- 如果
Supe
的所有示例都是专门化的Singleton
,那么应该如何消除它,而不使用任何隐式召唤或转换? - 其他情况下如何消除?
- 更新1**:需要注意的是,
v: Any
的类型在编译时是未知的,调用点也无法提供这样的信息。因此,当T1不能被解析为一个具体的类和/或运行时条件时,这个问题就不适用了。
- 更新1**:需要注意的是,
1条答案
按热度按时间4uqofj5v1#
在Scala 2中
为了克服类型擦除,在Scala 2中我们使用
scala.reflect.ClassTag
。或(方法2)
类似地,在Scala 3中
在Scala 3中,使用
scala.reflect.Typeable
(scala.reflect.TypeTest
)代替ClassTag
。关于方法2,在Scala 3中没有办法隐藏隐式的名称,所以让我们把它放在一个局部作用域中,这样就不会在对象隐式作用域中找到它
我仍然认为
given
或using
在所有情况下都可以避免,这两种方法都需要大量的样板,特别是在模式匹配包含大量联合或交集类型时在上一个示例中,使用
T1 with Int
或T1 {def v: Int}
等类型添加每个新case都需要一个Typeable,这在许多情况下是不可行的。ClassTag
,TypeTag
、shapeless.Typeable
/TypeCase
(Scala 2)、TypeTest
/Typeable
、Shapeless-3Typeable
(Scala 3)是克服类型擦除的标准工具。在运行时匹配类型对于模式匹配来说并不常见。如果您的业务逻辑是基于类型的,那么您可能根本不需要模式匹配,也许类型类会是更好的选择或
使用
T1 with Int
或T1 {def v: Int}
等类型添加每个新案例都需要使用Typeable
,这在许多情况下是不可行的。