如何模式匹配scala列表的head和tail类型?

时间:2015-12-06 07:16:46

标签: scala pattern-matching

我想pattern match list scala head的{​​{1}}的{​​{1}}的{​​{1}}和<{1}}类型的tail

class Solution07 extends FlatSpec with ShouldMatchers {
  "plain recursive flatten" should "flatten a list" in {
    val list1 = List(List(1, 1), 2, List(3, List(5, 8)))
    val list1Flattened = List(1, 1, 2, 3, 5, 8)

    flattenRecur(list1) should be (list1Flattened)
  }

  def flattenRecur(ls: List[Any]): List[Int] = ls match {
    case (head: Int) :: (tail: List[Any]) => head :: flattenRecur(tail)
    case (head: List[Int]) :: (tail: List[Any]) => head.head :: flattenRecur(head.tail :: tail)
    case (head: List[Any]) :: (tail: List[Any]) => flattenRecur(head) :: flattenRecur(tail) // non-variable type... on this line.
  }
}

我明白了:

  

错误:(18,17)类型模式中的非变量类型参数Int   List [Int](List [Int]的基础)是未选中的,因为它是   通过擦除消除       case(head:List [Int])::(tail:List [Any])=&gt; head.head :: flattenRecur(head.tail :: tail)                   ^

我错过了什么?我怎么可能在列表的headtail 类型上进行模式匹配?

2 个答案:

答案 0 :(得分:9)

我同意@Andreas解决方案与HList是解决问题的一个很好的例子,但我仍然不明白这个问题是什么:

 def flatten(ls: List[_]): List[Int] = ls match {
    case Nil => Nil
    case (a: Int) :: tail => a :: flatten(tail)
    case (a: List[_]) :: tail => flatten(a) ::: flatten(tail)
    case _ :: tail => flatten(tail)
  }

然后:

println(flatten(List(List("one",9,8),3,"str",4,List(true,77,3.2)))) // List(9, 8, 3, 4, 77)

我在任务中看不到类型擦除的任何问题,因为您实际上并不需要测试被删除的类型。我故意在我的示例中跳过了所有已删除的类型 - 以显示此信息。类型擦除不会清除列表元素的类型信息,它只清除您在我的案例中有Any_的列表通用的类型信息 - 所以您根本不需要它。如果我没有错过某些内容,那么在您的示例中,类型根本不会被删除,因为无论如何您几乎无处不在Any

答案 1 :(得分:1)

你受到了对象系统给出的限制:

List[Int]Int的唯一共同父级是Any

因此,推理系统只能安全地假设您可以返回Any。建议@jwvh的解决方案是可行的,但可能存在运行时异常的危险。

如果您想以类型安全的方式解决问题,可以选择使用无形库https://github.com/milessabin/shapelessHListhttps://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#heterogenous-lists