2014-01-06 2 views
2

Я пытаюсь написать фабричный метод, который возвращает Foo [T: ClassManifest] (который мне нужен из-за требований библиотеки, к которой я передаю результат), не зная конкретно, что такое T. Мой код эквивалентен:Как создать фабричный метод в scala, который возвращает класс, общий параметр которого ограничен 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

Тип результата: parse: Foo[_], поэтому T неизвестен. Вы не можете получить ClassManifest для неизвестного типа. Просто удалите ClassManifestT) от 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}") 
+0

@NathanKronenfeld: Я думаю, естественный способ, чтобы добавить его в поле 'Foo'. См. Обновление. – senia

+0

, когда я добавляю 'val manifest = неявно [ClassManifest [T]]' to 'Foo', это, похоже, не имеет никакого значения - я получаю точно такую ​​же ошибку. Если вместо этого я попробую ваш второй подход и передам манифест класса отдельно, я не вижу, как будет выглядеть манифест класса и реальные возвращаемые значения - компилятор не будет знать, что это манифест класса правильного типа, не так ли? –

+0

Вам не нужно 'T: ClassManifest' в' printIt'. См. Обновление. – senia

Смежные вопросы