【问题标题】:Create object at runtime which have the same internal contents在运行时创建具有相同内部内容的对象
【发布时间】:2020-01-23 19:12:06
【问题描述】:

我正在执行创建具有相同内部内容的对象的重复任务,因此我想创建一个通用方法来帮助我实现这一目标。

内部对象如下

case class Data(value: Int)

我有一个基本特征如下

trait Base

有几个类扩展了这个特性

case class A(data: Data) extends Base
case class B(data: Data) extends Base
case class C(data: Data) extends Base

我试图编写的用于创建对象的通用方法

def getObject[T <: Base](data: Data, t: T) = {
  T(data)
}

但是,在尝试这样做时,我收到一个编译时错误,提示

Cannot resolve symbol T

你能告诉我我在这个方法实现中缺少什么吗? 注意:- 这是我在代码中尝试做的一个非常简单的实现。

【问题讨论】:

    标签: scala generics return-current-type


    【解决方案1】:

    由于type-erasure,您不能使用泛型类型来创建对象的新实例。

    您可以使用ClassTag 在运行时捕获一个 T 类:

    case class Data(value: Int)
    
    trait Base
    
    case class A(data: Data) extends Base
    case class B(data: Data) extends Base
    case class C(data: Data) extends Base
    
    def getObject[T <: Base](data: Data)(implicit ct: ClassTag[T]): T = 
      ct.runtimeClass.getDeclaredConstructors.head.newInstance(data).asInstanceOf[T]
    
    
    val a: A = getObject[A](Data(1))
    val b: B = getObject[B](Data(2))
    val c: C = getObject[C](Data(3))
    

    正如 cchantep 所注意到的,它有一个缺点,如果您的案例类没有带有单个参数 Data 的构造函数,则此函数将在运行时失败。

    【讨论】:

    • 或者一个工厂类型的类可以避免不安全的运行时反射
    • @Krzysztof Atłasik 感谢您的回答。赞成它,但更喜欢类型类实现,因为它是类型安全的
    【解决方案2】:

    考虑使用typeclass 解决编译时安全问题

    final case class Data(value: Int)
    final case class A(data: Data)
    final case class B(data: Data)
    final case class C(data: Data)
    
    trait BaseFactory[T] {
      def apply(data: Data): T
    }
    
    object BaseFactory {
      def apply[T](data: Data)(implicit ev: BaseFactory[T]): T = ev.apply(data)
      implicit val aBaseFactory: BaseFactory[A] = (data: Data) => A(data)
      implicit val bBaseFactory: BaseFactory[B] = (data: Data) => B(data)
      implicit val cBaseFactory: BaseFactory[C] = (data: Data) => C(data)
    }
    
    val data = Data(42)
    BaseFactory[A](data)   // res0: A = A(Data(42))
    BaseFactory[B](data)   // res1: B = B(Data(42)) 
    BaseFactory[C](data)   // res2: C = C(Data(42))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 1970-01-01
      • 1970-01-01
      • 2010-12-30
      • 2018-12-17
      • 2021-02-02
      • 1970-01-01
      相关资源
      最近更新 更多