泛型列表上的模式匹配

Pattern matching on a list of generics

我有一个 class,其中包含一个泛型序列,例如:

sealed trait Interface {}

case class Imp1() extends Interface {}
case class Imp2() extends Interface {}

case class Wrapper[+I <: Interface](interface: I) {}

case class WrapperList(list: Seq[Wrapper[Interface]]) {
    ...
}

WrapperList 中,我希望能够遍历每个类型的包装序列和模式匹配,例如

def getImp1s(remaining: Seq[Wrapper[Interface]] = list): Seq[Wrapper[Imp1]] = {
  if (remaining.length == 0) Seq()
  else remaining.head match {
    case wrapper: Wrapper[Imp1] => get(remaining.tail) :+ wrapper
    case _                      => get(remaining.tail)
  }
}

你可能猜到我 运行 喜欢

non-variable type argument Playground.Imp1 in type pattern Playground.Wrapper[Playground.Imp1] is unchecked since it is eliminated by erasure

为了克服这个问题,我觉得我可以使用 TypeTagsClassTags 来保留类型,例如:

case class Wrapper[+I <: Interface](interface: I)(implicit tag: TypeTag[I]) {}

但这似乎不起作用,我仍然收到相同的警告。有人可以解释我如何使用 TypeTag 进行匹配吗?我宁愿避免创建扩展通用抽象 class 的通用 class 的具体版本,但请理解这可能是最简单的解决方案。

感谢您的帮助:)

尝试

import shapeless.TypeCase

val `Wrapper[Imp1]` = TypeCase[Wrapper[Imp1]]

def getImp1s(remaining: Seq[Wrapper[Interface]]): Seq[Wrapper[Imp1]] = {
  if (remaining.isEmpty) Seq()
  else remaining.head match {
    case `Wrapper[Imp1]`(wrapper) => getImp1s(remaining.tail) :+ wrapper
    case _                        => getImp1s(remaining.tail)
  }
}

getImp1s(Seq(Wrapper(Imp1()), Wrapper(Imp2()), Wrapper(new Interface {}))) 
// List(Wrapper(Imp1()))
getImp1s(Seq(Wrapper(Imp2()), Wrapper(Imp1()), Wrapper(new Interface {}))) 
// List(Wrapper(Imp1()))

不用 Shapeless 和自定义提取器也可以实现同样的效果

object `Wrapper[Imp1]` {
  def unapply(arg: Any): Option[Wrapper[Imp1]] = arg match {
    case Wrapper(Imp1()) => Some(Wrapper(Imp1()))
    case _               => None
  }
}

或直接

def getImp1s(remaining: Seq[Wrapper[Interface]]): Seq[Wrapper[Imp1]] = {
  if (remaining.isEmpty) Seq()
  else remaining.head match {
    case Wrapper(Imp1()) => getImp1s(remaining.tail) :+ Wrapper(Imp1())
    case _               => getImp1s(remaining.tail)
  }
}

def getImp1s(remaining: Seq[Wrapper[Interface]]): Seq[Wrapper[Imp1]] = {
  if (remaining.isEmpty) Seq()
  else remaining.head match {
    case Wrapper(_: Imp1) => getImp1s(remaining.tail) :+ Wrapper(Imp1())
    case _                => getImp1s(remaining.tail)
  }
}