如何在scala中创建一个工厂方法,返回一个其泛型参数被限制为ClassManifest的类?

时间:2014-01-06 18:31:14

标签: scala generics manifest

我正在尝试编写一个返回Foo [T:ClassManifest]的工厂方法(由于我传递结果的库的要求,我需要它),而不知道具体是什么。我的代码相当于:

class Foo[T: ClassManifest] (t: T) {
  def getValue: T = t

  override def toString: String = "Foo["+t+": "+t.getClass().getName()+"]"
}

object FooFactory {
  def parse (value: String): Foo[_] = {
    val rest = value.substring(1)
    value.head match {
      case 's' => new Foo[String](rest)
      case 'i' => new Foo[Int](rest.trim.toInt)
      case 'd' => new Foo[Double](rest.trim.toDouble)
    }
  }
}


class FactoryTestSuite extends FunSuite {
  def printIt [T: ClassManifest] (t: Foo[T]): Unit =
    println(t)

  test("Creation") {
    printIt(FooFactory.parse("sabc"))
    printIt(FooFactory.parse("i123"))
    printIt(FooFactory.parse("d1.23"))
  }
}

这不会编译 - 每个创建测试行都抱怨它could not find implicit value for evidence parameter of type ClassManifest[_$1]

有没有办法做到这一点?或者ClassManifest的编译时要求是否使得这根本不可能?

1 个答案:

答案 0 :(得分:1)

parse的结果类型为Foo[_],因此T未知。对于未知类型,您无法获得ClassManifest。只需从ClassManifest

中删除T(和printIt)即可
def printIt(t: Foo[_]): Unit = println(t)

printIt(FooFactory.parse("sabc"))
// Foo[abc: java.lang.String]

printIt(FooFactory.parse("i123"))
// Foo[123: java.lang.Integer]

printIt(FooFactory.parse("d1.23"))
// Foo[1.23: java.lang.Double]

此处解析了ClassManifest[T]构造函数的Foo类型的隐式参数:

case 's' => new Foo[String](rest)

编译器知道T这里是String。它可以创建类型为ClassManifest[String]的隐式参数。

要在方法ClassManifest中获取printIt,您可以将其添加为课程Foo中的字段:

class Foo[T: ClassManifest] (t: T) {
  val manifest = implicitly[ClassManifest[T]]
  ...
}

def printIt (t: Foo[_]): Unit =
  println(s"t=$t, manifest=${t.manifest}")