Как сопоставить типы head и tail в списке scala?
Я хочу pattern match
на разных сегментах a list
на scala
о типах head
и 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]) => head.head :: flattenRecur (head.хвост: хвост) ^
что я не хватает? как это возможно для меня, чтобы шаблон совпадения на head
и tail
' s типы из списка?
3 ответов
Я согласен, что решение @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)
Я не вижу никаких проблем с стиранием типов в вашей задаче, потому что вам на самом деле не нужно тестировать типы, которые стираются. Я намеренно пропустил все удаленные типы в моем примере - чтобы показать это. Тип erasure не очищает информацию о типе элементов списка, это очищает только информацию о типе списка generic, который у вас есть Any
или _
в моем случае - так что вам не нужно. Если я не упускаю что-то, в вашем примере типы вообще не стираются, потому что у вас все равно есть Any
почти везде.
вас поражают ограничения, заданные объектной системой:
единственный общий родитель для List[Int]
и Int
is Any
поэтому из-за этого система вывода может только безопасно предположить, что вы можете вернуть Any
. Предлагаемое решение @jwvh выполнимо, но имеет возможную опасность исключений во время выполнения.
если вы хотите решить проблему в typesafe способом вариант может быть использовать HList
бесформенной библиотеки https://github.com/milessabin/shapeless : https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#heterogenous-lists
из-за стирания типа вы можете прибегнуть к проверке каждого элемента.
def flattenRecur(ls: List[Any]): List[Int] = ls match {
case head :: tail if (head.isInstanceOf[Int])
=> head.asInstanceOf[Int] :: flattenRecur(tail)
case head :: tail if (head.isInstanceOf[List[Any]])
=> flattenRecur(head.asInstanceOf[List[Any]]) ++
flattenRecur(tail)
case _ :: tail => flattenRecur(tail)
case _ => Nil
}
который, похоже, работает:
scala> flattenRecur(List(List("one",9,8),3,"str",4,List(true,77,3.2)))
res8: List[Int] = List(9, 8, 3, 4, 77)
но, как общее правило, избежать Any
обычно стоит затраченных усилий.