【问题标题】:Scala - Conditionally add traits to class instance during constructionScala - 在构造期间有条件地向类实例添加特征
【发布时间】:2026-01-03 20:20:02
【问题描述】:

我正在尝试创建一个类的实例并根据某些条件混合某些特征。所以给定:

class Foo

trait A

trait B

我可以做类似的事情

if (fooType == "A")
  new Foo with A
else if (footType == "B")
  new Foo With B

对于像这样的简单情况,这很好用。我的问题是可以根据其他条件将多个特征混合到同一个实例中,并且最重要的是,被实例化的类有相当多的参数,所以这会导致一个非常丑陋的条件块。

我想做的是事先确定要混合的特征,例如(我知道这不是合法的 scala 代码):

val t1 = fooType match {
  case "a" => A
  case "b" => B
}

val t2 = fooScope match {
  case "x" => X
  case "y" => Y
}

new Foo with t1 with t2

其中 A、B、X 和 Y 都是先前定义的特征,而 fooType 和 fooScope 是我的函数的输入。我不确定是否有任何我可以做的与上述有点相似的事情,但任何建议都将不胜感激。

谢谢

【问题讨论】:

  • 你想要的很可能不是必需的。如果不同 Foo 的行为应该不同,您可以轻松地将条件语句添加到它们的方法实现中。无需更改继承层次结构。

标签: scala mixins traits


【解决方案1】:

我相信你想做的事情是不可能的。在 Scala 中,对象的类型必须在编译时知道,所以 new Foo with A 有效,但 new Foo with t1 不能,因为 t1 仅在运行时解析。

【讨论】:

    【解决方案2】:

    有几个想法可以混合在一起......

    非运行时工厂

    使用您所说的充满条件的复杂代码,将它们放在一起列出可能的组合。然后可以使用此列表来创建所有类。很简单的例子:

    (for(a <- Seq("A", "B"); b <- Seq("X", "Y")) yield
      s"class Foo$a$b extends $a with $b").mkString("\n")
    

    这将产生以下内容:

    class FooAX extends A with X
    class FooBX extends B with X
    class FooAY extends A with Y
    class FooBY extends B with Y
    

    那么简单:

    val ax = new FooAX()
    

    这很好,因为它是非常强类型的,而且每个人都可以准确地知道它是什么类型,而不会让人头疼。

    代表团

    这里有一个有趣的非反射/类加载器技术:

    https://github.com/b-studios/MixinComposition

    它将特征作为参数,然后简单地委托给适当的特征。

    【讨论】: