指定调用未知泛型类型的方法

时间:2014-10-16 17:39:57

标签: scala

假设我有以下代码:

abstract class GenericType[T]{
    val someSeq: Seq[T]

    def list() = for(item <- someSeq) println(item)
}

class ConcreteType extends GenericType[Int] {
    val someSeq = Seq(1, 2, 3)
}

object MyApp {
    def main(args: Array[String]) {
        val ct = new ConcreteType
        ct.list()
    }
}

这只是打印出1 2 3(在单独的行上)。但是假设我想要创建一个泛型类型的实例来调用T的某个方法。例如,假设我想调用整数的max方法。我如何指定要调用的方法?

我假设我可以在抽象类中创建一个值,该类包含在每个item上调用的方法,并在具体类中指定该方法。

换句话说,我想最终得到类似的东西:

abstract class GenericType[T]{
    val someSeq: Seq[T]
    val methodToCall: ???

    def list() = for(item <- someSeq) println(item.methodToCall)
}

class ConcreteType extends GenericType[SomeType] {
    val someSeq = Seq(1, 2, 3)
    val methodToCall = ???.max(_, 2)
}

并期望main然后打印出2 2 3(即for(item <- someSeq) println(item.max(_, 2))的结果)。

3 个答案:

答案 0 :(得分:3)

你不能这样做。您只能返回值,方法不是值。但是,您可以使用函数并传递lambda或通过η-expansion将方法转换为函数。

abstract class GenericType[T] {
  def someSeq: Seq[T]

  type MapResult
  def map: T => MapResult

  def list() = someSeq.foreach(map andThen println)
}

class ConcreteType extends GenericType[Int] {
  override val someSeq = Seq(1, 2, 3)

  override type MapResult = Int
  override val map = 2.max(_)
}

答案 1 :(得分:1)

我个人会尝试使用类型类。这是一个例子:

  trait MethodToCall[T, R] {
    def invoke(obj: T): R
  }

  implicit object IntToCall extends MethodToCall[Int, Int] {
    override def invoke(obj: Int): Int = obj.max(2)
  }

  abstract class GenericType[T]{
    def someSeq: Seq[T]

    def list[R](implicit mtc: MethodToCall[T, R]) =
      for(item <- someSeq) println(mtc.invoke(item))
  }

  class ConcreteType extends GenericType[Int] {
    val someSeq = Seq(1, 2, 3)
  }

  new ConcreteType().list[Int]

答案 2 :(得分:0)

你需要指定'mtehodToCall'的返回类型,我使用T代表

  abstract class GenericType[T]{
    def someSeq: Seq[T]
    def methodToCall: T => T

    def list() = for(item <- someSeq) println(methodToCall(item))
  }

  class ConcreteType extends GenericType[Int] {
    val someSeq = Seq(1, 2, 3)
    val methodToCall: Int => Int = math.max(_, 2)
  }

  new ConcreteType().list()