2012-08-11 126 views
0

我有一个类层次结构Item s,每个实例都需要一个相应的ItemTemplate实例作为构造函数参数。我想编写一个通用的功能,给它ItemItemTemplate类型的参数,使用它像这样的实例任何Item子类:实例化一个没有无参数构造函数的类型参数

val newItem = instantiateItem[ItemClass, TemplateClass](templateInstance) 

了一些研究之后,我现在有

def instantiateItem[I, T](implicit mf: Manifest[I], template: T): I = { 
    val constructor = mf.erasure.getConstructor(classOf[T]) 
    constructor.newInstance(template).asInstanceOf[I] 
} 

但这并不进行编译时,classOf[T]给需要

类类型的错误,但t上找不到

我试图取代classOf[T]classManifest[CM].erasure但CM必须是上下文一定到ClassManifest这不工作,显然这是不可能的使用限制类型参数与隐式参数。

是否有可能做我想在这里?

回答

1

您只需致电template.getClass即可获得template课程。它要求template是的AnyRef一个亚型,所以无论你将它转换为AnyRef(迫使原始类型的拳击)或您添加的上限为T

def instantiateItem[I, T <: AnyRef](implicit mf: Manifest[I], template: T): I = { 
    val constructor = mf.erasure.getConstructor(template.getClass) 
    constructor.newInstance(template).asInstanceOf[I] 
} 

如果你想在template传递明确,作为由你的问题中的代码表示,你需要分离隐式和显式参数,例如

def instantiateItem[I, T <: AnyRef](template: T)(implicit mf: Manifest[I]): I = { 
    val constructor = mf.erasure.getConstructor(template.getClass) 
    constructor.newInstance(template).asInstanceOf[I] 
} 

又名

def instantiateItem[I : Manifest, T <: AnyRef](template: T): I = { 
    val mf = implicitly[Manifest[I]] 
    val constructor = mf.erasure.getConstructor(template.getClass) 
    constructor.newInstance(template).asInstanceOf[I] 
} 

一般来说如果可能的话,你可能会避免在所有使用反射与精心的设计:

trait ItemCompanion[I,T] { 
    def instantiateItem(template: T): I 
} 

object TestItem extends ItemCompanion[TestItem, TestTemplate] { 
    implicit def self: ItemCompanion[TestItem, TestTemplate] = this 
    def instantiateItem(template: TestTemplate): TestItem = new TestItem(template) 
} 
class TestItem(template: TestTemplate) 
trait TestTemplate 

// try out 
def instantiateItem[I, T](implicit ic: ItemCompanion[I, T], t: T): I = 
    ic.instantiateItem(t) 

implicit val temp: TestTemplate = new TestTemplate {} 
instantiateItem[TestItem, TestTemplate] 
+0

这将编译被弃用,但我有一个问题,称它: 没有足够的论据方法instantiateItem:(隐式MF:舱单[I],隐模板:T)我。未指定的值参数模板。 – hezamu 2012-08-11 15:57:23

+0

你的通话看起来如何?它应该是'instantiateItem [TestItem,TestTemplate]' – 2012-08-11 16:05:48

+0

在你的问题中你明确地传递了'template'参数。然后你必须传入_both_参数(首先是清单,然后是模板)。如果你想要_that_,你应该用两个参数列表来定义方法,例如'def instantiateItem [I,T <:AnyRef](template:T)(implicit mf:Manifest [I]):I' – 2012-08-11 16:08:37

1

这些修正你的代码应该做的绝招:

def instantiateItem[I : Manifest, T <: AnyRef : Manifest](template: T): I = { 
    val constructor = manifest[I].erasure.getConstructor(manifest[T].erasure) 
    constructor.newInstance(template).asInstanceOf[I] 
} 

I : Manifest语法是隐式参数的首选糖类版本。

请注意,由于斯卡拉2.10 Manifest将有利于TypeTag

+0

@hezamu对。 “T”必须限制为“AnyRef”子类型。请参阅更新 - 它编译。 – 2012-08-11 16:04:40

+0

是的,现在它编译。我仍然不清楚该怎么称呼它,我在这个问题中描述的方式并不适用于此。 – hezamu 2012-08-11 16:07:59

+0

@hezamu您在问题中描述的内容完全适用于此,但它有点多余,因为'T'类型可以从'template'参数中解析出来,所以不需要指定。换句话说,你可以像这样使用它:'instantiateItem [ItemClass](templateInstance)' – 2012-08-11 18:28:32

相关问题