Scala - 如何创建匿名类并避免隐藏参数名称

时间:2014-09-04 00:05:00

标签: scala

我经常遇到这样的情况,即我有一些特征的工厂方法,并且参数的名称与特征的成员冲突导致它们被隐藏:

trait MyTrait {
    val a: Int
    val b: String
}

object MyTrait {
    def apply(a: Int, b: String): MyTrait = new MyTrait {
        val a = a // Recursive infinite loop.
        val b = b
    }
}

所以通常我必须做一些丑陋的事情:

    def apply(aA: Int, bB: String): MyTrait = new MyTrait {
      val a = aA
      val b = bB
    }

或制作参数的本地副本:

    def apply(a: Int, b: String): MyTrait = {
      val localA = a
      val localB = b

      new MyTrait {          
          val a = localA
          val b = localB
    }

我希望apply方法的参数与我的特征成员相同,以便在使用命名参数时客户端代码可以很好地读取: MyTrait(a=3,b="123")

是否有一个更整洁的机制让我捕获定义参数参数的外部范围,但是匿名类还没有?例如:

    def apply(a: Int, b: String): MyTrait = { outer =>
        new MyTrait {
            val a = outer.a
            val b = outer.b
        }
    }

谢谢!

2 个答案:

答案 0 :(得分:2)

如果我们需要创建一个实例,为什么不将它委托给构造函数。所以我可以想到这个黑客:

trait MyTrait {
  def a: Int
  def b: String
}

object MyTrait {
  private class MkMyTrait(val a: Int, val b: String) extends MyTrait
  def apply(a: Int, b: String): MyTrait = new MkMyTrait(a, b)
}

答案 1 :(得分:2)

我对骗局的回答,并没有节省多少:

trait T { val t: Int }
object T {
  def apply(t: Int): T = new {
    private[this] val x = t
  } with T {
    val t = x
  }
}

另外,-optimise并没有摆脱这个领域。

这是一个不同的想法:别名为param名称。

很快,我们将能够有选择地过滤警告,因此可以忽略启用弃用时生成的警告:

scala> :pa
// Entering paste mode (ctrl-D to finish)

trait T { val t: Int }
object T {
  def apply(@deprecatedName('t) t0: Int): T = new T { val t = t0 }
}

// Exiting paste mode, now interpreting.

defined trait T
defined object T

scala> T(t = 42)
warning: there was one deprecation warning; re-run with -deprecation for details
res1: T = T$$anon$1@6ea1bcdc