在Scala中使用通用可遍历参数递归调用方法类型不匹配

时间:2017-01-02 07:35:43

标签: scala generics

我可以创建一个(愚蠢的)Traversable包装器,它接受一些Traversable类型并使用以下代码返回相同的import scala.collection.TraversableLike def dropN[E, T <: Traversable[E]] (xs: T with TraversableLike[E, T], n: Int): T = { xs.drop(n) } dropN(0 to 3, 1) // returns: Range 1 to 3 类型:

// basically finds the tail
def dropNR[E, T <: Traversable[E]]
(xs: T with TraversableLike[E, T]): T =
{
    if (xs.size > 1) dropNR[E,T](xs.drop(1)) else xs
}

但是,如果我尝试使用递归来创建类似的函数:

Type mismatch: expected T with TraversableLike[E, T], actual: T

我收到以下消息:def recurse[E, T <: Traversable[E]] (xs: T with TraversableLike[E, T]): T = { recurse[E,T](xs) }

同时,一个纯粹的传递递归方法没有编译错误(但显然会永远递归)

Type mismatch

为什么我在使用drop时获得service

2 个答案:

答案 0 :(得分:1)

Because xs.drop(1) returns a T, not the mixed in T with Traversable[E] type you mix in to the original xs. In recurse, you're returning the unmodified collection, which is why it works.

I'm not sure why you need all those extra type parameters (perhaps I'm missing something), this should do:

def dropNR[E](xs: Traversable[E]): Traversable[E] = {
  if (xs.size > 1) dropNR[E](xs.drop(1)) else xs
}

答案 1 :(得分:0)

原来我需要使用scala> :pa // Entering paste mode (ctrl-D to finish) import scala.collection.generic.CanBuildFrom def dropR[E, D[E] <: Traversable[E]](xs: D[E]) (implicit cbf: CanBuildFrom[D[E], E, D[E]]): D[E] = { if (xs.size > 1) dropR[E,D](xs.drop(1).to[D]) else xs.to[D] } // Exiting paste mode, now interpreting. import scala.collection.generic.CanBuildFrom dropR: [E, D[E] <: Traversable[E]](xs: D[E])(implicit cbf: scala.collection.generic.CanBuildFrom[D[E],E,D[E]])D[E] scala> val l = List(1,2,3) l: List[Int] = List(1, 2, 3) scala> dropR(l) res0: List[Int] = List(3) scala> dropR(l.toSeq) res1: scala.collection.immutable.Seq[Int] = List(3) scala> dropR(l.toSet) res2: scala.collection.immutable.Set[Int] = Set(3) scala> dropR(l.toBuffer) res3: scala.collection.mutable.Buffer[Int] = ArrayBuffer(3)

document.querySelector('#assets').addEventListener('loaded', function (){
   // display #startbutton and hide #loadingbutton
   document.getElementById('startbutton').style.display = "inline";
   document.getElementById('loadingbutton').style.display = "none";
});