scala – 如何构建泛型类型的匿名实例?
考虑这个简单的类:
class MyClass(p: (String,String) *) { val params: Map[String,String] = p.toMap } 还有一个扩展它的类: class SomeOtherClass(p: (String,String) *) extends MyClass(p: _*) 我想从MyClass中删除构造函数,以避免在扩展它的所有内容中携带初始化参数(可能有很多类型).相反,我更喜欢扩展MyClass的类型的伴随对象继承某种构建器方法. class MyClass { val param = Map.empty[String,String] // some member with a default value } trait MyClassBuilder[A <: MyClass] { def apply(p: (String,String) *): A = ??? } 基本上应用应该做这样的事情: new A { override val param = p.toMap } 显然,上面的代码无法正常工作.我们的想法是使用这样的子类型: class SomeOtherClass extends MyClass object SomeOtherClass extends MyClassBuilder[SomeOtherClass] { // object specific things.. } 然后SomeOtherClass将依赖继承的apply方法来创建自身的实例.看起来这样的事情可能是用反射或宏来实现的,但我真的不知道.为了清楚起见,我希望像SomeOtherClass这样的客户端代码根本不需要构造函数,这就是我想探索在泛型类型上创建匿名类的原因.它可能不是SomeOtherClass生成的,它可能是扩展MyClass的任何东西. 解决方法
这可能对您有所帮助:
import scala.reflect._ abstract class MyClassBuilder[A <: MyClass: ClassTag] { def apply() = classTag[A].runtimeClass.newInstance.asInstanceOf[A] } 您可能会发现我没有在这里传递(String,String)*,因为它们是实例化的冗余.无论如何,你可以在这里访问整个A的实例,所以至少你可以在实例化后更改参数.这并不是你想要的 – 因为你似乎在寻找一种在运行时扩展SomeOtherClass的方法.但是,在scala中运行时创建新类型是不可能的,但您可能会将其视为原型 – 只需在apply()中使用SomeOtherClass实例并进行一次变异: import scala.reflect._ object Ctx { class MyClass { private[Ctx] var _param = Map.empty[String,String] def param = _param } abstract class MyClassBuilder[A <: MyClass: ClassTag] { def apply(p: (String,String) *) = { val i = classTag[A].runtimeClass.newInstance.asInstanceOf[A] i._param = Map(p: _*) i } } } scala> class MySpecialClass extends Ctx.MyClass defined class MySpecialClass scala> object MySpecialBuilder extends Ctx.MyClassBuilder[MySpecialClass] defined module MySpecialBuilder scala> MySpecialBuilder("A" -> "b") res12: MySpecialClass = MySpecialClass@2871ed4a scala> res12.param res13: scala.collection.immutable.Map[String,String] = Map(A -> b) 否则你必须处理编译时反射. 一个有趣的替代方案是extensible records(Shapeless2) – 它们实际上允许你逐个构建新类型,但你必须处理HList而不是那里的类: import shapeless._ ; import syntax.singleton._ ; import record._ import shapeless.ops.record.Updater import scala.reflect.runtime.universe._ val param = Witness("param") val someFunW = Witness("someFun") //defining classess (instead of "class MyClass") type Param = Map[String,String] with KeyTag[param.T,Map[String,String]] type SomeFun = (String => String) with KeyTag[someFunW.T,(String => String)] type MyClass = Param :: HNil type MySpecialClass = SomeFun :: MyClass def someFun(s: String) = s + "A" //defining default values (instead of "val param = ...") def newMyClass[T <: HList : TypeTag]: T = ( if (typeTag[T] == typeTag[MyClass]) (param ->> Map.empty[String,String]) :: HNil else if (typeTag[T] == typeTag[MySpecialClass]) (someFunW ->> someFun _) :: newMyClass[MyClass] else HNil ).asInstanceOf[T] //Defining builder def buildWithParam[T <: HList: TypeTag](p: Map[String,String])(implicit ev: Updater[T,Param]) = newMyClass[T] + ("param" ->> p) scala> buildWithParam[MySpecialClass](Map("a" -> "v")) res6: ... = <function1> :: Map(a -> v) :: HNil scala> res6("someFun").apply("a") res7: String = aA scala> buildWithParam[MyClass](Map("a" -> "v")) res8: ... = Map(a -> v) :: HNil (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |