scala – 用implicits模拟部分类型参数推断?
我在
Scala中为构造函数注入创建了一个简单的依赖注入框架.这个想法是DI’d的对象将它们所需的服务放在它们的构造函数中,就像常规参数一样,并实现一个类型类,确定它们从容器中取出哪些参数,以及用户在实例化时传递哪些参数.
所以,它应该看起来像: trait Container { private singletons: Map[Class,AnyRef] def getSingleton[T: Manifest] = singletons(implicitly[Manifest[T]].erasure).asInstanceOf[T] ... methods for adding singletons,etc ... } class Foo(arg: String,svc: FooService) { ... } trait Constructor[T] { ??? } object FooConstructor extends Constructor[Foo] { def construct(arg: String)(implicit container: Container) = new Foo(arg,container.getSingleton[FooService]) } 现在我基本上希望能够有一个名为construct的方法,我可以将其称为construct [Foo](“asd”)并获取一个新的Foo实例,并将“asd”传入构造函数,并获得FooService从本地容器中传入并传递给构造函数.这个想法是它应该为Foo获取Constructor类型类的实例,并且以类型安全的方式,知道它应该具有的参数的数量和类型.此外,这是困难的部分,我不想写出参数的类型 – 只是要构造的对象. 我尝试了几件事: trait Constructor1[T,A] { def construct(arg: A): T } trait Constructor2[T,A1,A2] { def construct(arg1: A1,arg2: A2): T } def construct[T,A](arg1: A): T = implicitly[Constructor1[T,A]].construct(arg1) ... 这种方法不起作用,因为它似乎是为了“召唤”构造函数类型类实例,我们需要编写参数的类型,这是很多讨厌的样板: construct[Foo,String]("asd") // yuck! 有没有办法使用类型类(或其他任何东西)来排序部分推断类型参数?我们在构造函数实例定义中定义了Foo的构造函数参数的类型,因此如果我们可以召唤实例,我们应该能够调用构造并获得正确的参数类型.问题是获取该实例而不必指定构造函数类型参数.我已经玩了很多不同的想法,我觉得Scala的力量和技巧只需要我可以编写构造[Foo](“asd”)并让参数列表为类型安全.有任何想法吗? 更新:感谢Miles Sabin的优秀答案稍作修改,这里的方法只需要一个类型参数,适用于所有不同的参数列表长度.这是一种非常简单的方法,可以轻松地连接依赖项,而无需反映成本: trait Constructor1[T,A] { def construct(arg1: A)(implicit c: Container): T } trait Constructor2[T,A,B] { def construct(arg1: A,arg2: B)(implicit c: Container): T } implicit object FooConstructor extends Constructor1[Foo,String] { def construct(arg1: String)(implicit c: Container) = new Foo(arg1,c.getSingleton[FooService]) } implicit object BarConstructor extends Constructor2[Bar,String,Int] { def construct(arg1: String,arg2: Int)(implicit c: Container) = new Bar(arg1,arg2,c.getSingleton[FooService]) } class Construct[T] { def apply[A](arg1: A)(implicit ctor: Constructor1[T,A],container: Container) = ctor.construct(arg1) def apply[A,B](arg1: A,arg2: B)(implicit ctor: Constructor2[T,B],container: Container) = ctor.construct(arg1,arg2) } def construct[T] = new Construct[T] construct[Foo]("asd") construct[Bar]("asd",123) 解决方法
Scala中的类型参数推断是一个全有或全无的事情:如果您明确提供类型参数块的任何类型参数,那么您必须提供所有这些参数.因此,如果您只想提供一组类型参数,则必须安排它们属于单独的类型参数块.
在这种情况下,这样做的方法是将构造方法拆分为两个阶段:第一个,它采用显式类型参数并返回类似函数的值;第二个,它将类似函数的值应用于您希望推断类型的参数. 这是它可能会如何, // Function-like type class Construct1[T] { def apply[A](arg1: A)(implicit ctor : Constructor1[T,A]): T = ctor.construct(arg1) } def construct[T] = new Construct1[T] 调用construct [Foo]的结果是Construct1 [Foo]类型的值.这有一个带有类型参数的apply方法,可以推断出一个隐式参数,其类型由T和A决定.你现在要调用的调用如下所示, construct[Foo].apply("asd") // T explicit,A inferred as String Scala的语义加糖规则适用于此处,这意味着可以将其重写为, construct[Foo]("asd") 这正是你想要的结果. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |