加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何构建泛型类型的匿名实例?

发布时间:2020-12-16 18:31:05 所属栏目:安全 来源:网络整理
导读:考虑这个简单的类: class MyClass(p: (String,String) *) { val params: Map[String,String] = p.toMap} 还有一个扩展它的类: class SomeOtherClass(p: (String,String) *) extends MyClass(p: _*) 我想从MyClass中删除构造函数,以避免在扩展它的所有内容
考虑这个简单的类:

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读