如何在Scala的泛型方法中创建一个trait的实例?

8

我正在尝试使用此方法创建一个trait的实例

val inst = new Object with MyTrait

这个方法很有效,但我希望把它转换为生成器函数,例如:

object Creator {
  def create[T] : T = new Object with T
}

显然,我需要清单来解决类型擦除问题,但在此之前,我遇到了两个问题:

  1. 即使使用隐式清单,Scala仍要求T是一个trait。如何添加限制以创建[T],使T成为trait?

  2. 如果我选择使用Class.newInstance方法动态创建实例而不是使用“new”,那么我该如何指定“with”中的“new Object with T”?是否有可能在运行时动态创建新的具体mixin类型?

2个回答

15

我不确定你提问的动机是什么,但你可以考虑将T的工厂作为一个隐式参数传递。这被称为使用类型类特定多态性

object Test extends Application {
  trait Factory[T] {
    def apply: T
  }
  object Factory {
    /**
     * Construct a factory for type `T` that creates a new instance by
     * invoking the by-name parameter `t`
     */
    def apply[T](t: => T): Factory[T] = new Factory[T] {
      def apply = t
    }
  }

  // define a few traits...
  trait T1
  trait T2

  // ...and corresponding instances of the `Factory` type class.
  implicit val T1Factory: Factory[T1] = Factory(new T1{})
  implicit val T2Factory: Factory[T2] = Factory(new T2{})

  // Use a context bound to restrict type parameter T
  // by requiring an implicit parameter of type `Factory[T]`
  def create[T: Factory]: T = implicitly[Factory[T]].apply

  create[T1]
  create[T2]

}

在另一端的范围内,您可以在运行时调用编译器,如“这个答案”中详细介绍的那样回答“Scala中的动态mixin - 是否可能?”的问题。


谢谢,我可能需要使用这种方法。 我的用例是Java代理。我想编写一个可远程使用的库。因此,我需要为所有类定义接口,这很麻烦,因为我想公开所有内容。一种解决方案是将所有内容都编写为trait,然后我可以免费获得接口定义。create函数的目的是在代理连接的“具体”端实例化trait。 - ACyclic

8
即使使用清单文件,您也无法这样做。 代码“new Object with T”涉及创建一个新的匿名类,该类表示“Object with T”的组合。 要将其传递给您的“create”函数,您必须在运行时生成此新类(具有新的字节码),而Scala没有生成新类的工具。
一种策略是尝试将工厂方法的特殊功能转移到类的构造函数中,然后直接使用构造函数。
另一种可能的策略是创建转换函数(隐式或其他方式)以使用此类的特征。

这似乎是语言的一个有趣限制,但我不认为它不能通过在Scala中引入新的“动态”mixin支持来解决。trait代码已经可作为静态方法使用,所以线性查找可以在运行时计算而不是编译进类字节码。然后你只需要添加运行时类型检查,这样“asInstanceOf”就可以工作了。 - ACyclic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接