[英]Scala pattern-match on generics
我有一个“字符串”列表(类String的包装,名为Str),其中一些具有混合特征。 在某个时间点,我需要区分mixin特性以提供额外的功能。
我的代码可以恢复到这个并且它工作正常:
case class Str(s: String)
trait A
trait B
object GenericsPatternMatch extends {
def main(args: Array[String]): Unit = {
val listOfStr: Seq[Str] =
Seq(
Str("String"),
new Str("String A") with A, // Some trait mixins
new Str("String B") with B
)
println("A: " + selectStrA(listOfStr))
println("B: " + selectStrB(listOfStr))
}
val selectStrA: Seq[Str] => Seq[Str with A] = (strList: Seq[Str]) => strList.collect { case s: A => s }
val selectStrB: Seq[Str] => Seq[Str with B] = (strList: Seq[Str]) => strList.collect { case s: B => s }
}
为了根据DRY原则保留代码,我想生成selectStr函数。 我的第一次尝试是:
def selectStrType[T](strList: Seq[Str]): Seq[Str with T] =
strList.collect { case f: Str with T => f }
但是由于JVM运行时类型擦除功能(限制?),编译器发出警告并且它不起作用,很可能是因为它将匹配与Object的所有内容:
Warning:(31, 31) abstract type pattern T is unchecked since it is eliminated by erasure
strList.collect { case f: Str with T => f }
经过几个小时的搜索和学习,我想出了:
def selectStrType[T: ClassTag](strList: Seq[Str]): Seq[Str with T] =
strList.collect {
case f: Str if classTag[T].runtimeClass.isInstance(f) => f.asInstanceOf[Str with T]
}
通过这种方法,我现在可以选择这样的特定特征:
val selectStrA: Seq[Str] => Seq[Str with A] = (strList: Seq[Str]) => selectStrType[A](strList: Seq[Str])
val selectStrB: Seq[Str] => Seq[Str with B] = (strList: Seq[Str]) => selectStrType[B](strList: Seq[Str])
我相信可能有一种方法可以改进selectStrType函数,即:
你能帮助我吗?
您可以按如下方式定义方法,它将起作用。
def selectStrType[T: ClassTag](strList: Seq[Str]): Seq[Str with T] =
strList.collect { case f: T => f }
由于ClassTag
上下文绑定了一个类型匹配只是T
将起作用(理想情况下Str with T
也应该工作,但这似乎是一个限制)。 现在编译器知道f
具有类型Str
并且也类型为T
,或者换句话说就是Str with T
,因此编译。 它会做正确的事情:
scala> selectStrType[A](listOfStr)
res3: Seq[Str with A] = List(Str(String A))
scala> selectStrType[B](listOfStr)
res4: Seq[Str with B] = List(Str(String B))
编辑:更正,看起来这将适用于Scala 2.13 。 在2.12中,您需要帮助编译器:
def selectStrType[T: ClassTag](strList: Seq[Str]): Seq[Str with T] =
strList.collect { case f: T => f: Str with T }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.