如何让Scala编译器推断出这个函数的类型?

时间:2014-05-06 07:58:18

标签: scala generics type-inference

我有一个功能,我无法进行类型推断。完整的示例代码如下,但有问题的功能是:

def mapObjects[T, S <: HasGetter[T]](lst: GenSeq[S]): GenSeq[T] = {
  lst map {v => v.getT}
}

问题是调用mapObjects需要明确命名类型T和S.有没有办法编写这个函数的类型签名,以便推理正常工作?

工作示例代码:

import scala.collection.GenSeq

trait HasGetter[T] {
  def getT: T
}

class HasStringGetter(str: String) extends HasGetter[String] {
  override def getT = str
}

object TypeInferenceTest {
  def mapObjects[T, S <: HasGetter[T]](lst: GenSeq[S]): GenSeq[T] = {
    lst map {v => v.getT}
  }

  def tst {
    val objs = List(new HasStringGetter("abc"), new HasStringGetter("def"), new HasStringGetter("hij"))

    // Doesn't typecheck
    // val strs = mapObjects(objs)

    val strs = mapObjects[String, HasStringGetter](objs)
  }
}

1 个答案:

答案 0 :(得分:4)

如何:

def mapObjects[T](lst: GenSeq[HasGetter[T]]): GenSeq[T] = {
    lst map {v => v.getT}
  }

scala> mapObjects(objs)
res18: scala.collection.GenSeq[String] = List(abc, def, hij)

在您的案例中使用S <: HasGetter[T]没有任何明显优势,因为您只是在lst上执行地图并获取T类型的元素。并且函数的返回类型与类型S无关。因此,无需获得精确类型S

如果明确需要函数或函数体的返回类型来维护类型S <: HasGetter[T],则需要您的代码。但在这种情况下,没有必要保持这种类型。

此外GenSeq[+A]是协变型。因此,默认情况下,它可以接受参数中属于GenSeq[ <: HasGetter[_]]的类型。 GenSeq不是共同变体,它本来是一个不同的问题。