案例类和特征的线性化

Nic*_*las 10 scala traits case-class

假设我想编写一个case类Stepper,如下所示:

case class Stepper(step: Int) {def apply(x: Int) = x + step}
Run Code Online (Sandbox Code Playgroud)

它带有一个很好的toString实现:

scala> Stepper(42).toString
res0: String = Stepper(42)
Run Code Online (Sandbox Code Playgroud)

但它不是真正的功能:

scala> Some(2) map Stepper(2)
<console>:10: error: type mismatch;
 found   : Stepper
 required: Int => ?
              Some(2) map Stepper(2)
Run Code Online (Sandbox Code Playgroud)

解决方法是实现Function特性......

case class Stepper(step: Int) extends (Int => Int) {def apply(x: Int) = x + step}
Run Code Online (Sandbox Code Playgroud)

但是,我不能再免费获得一个很好的toString实现了:

scala> Stepper(42).toString
res2: java.lang.String = <function1>
Run Code Online (Sandbox Code Playgroud)

然后,问题是:我可以充分利用这两个世界吗?有没有一个解决方案,我有漂亮的toString自由执行特点的实现Function.换句话说,有没有办法以最终应用case class语法糖的方式应用线性化?

Vla*_*dim 8

这个问题与线性化无关.在case-classes中toString是一种由编译器自动生成的方法,当且仅当Any.toString在end-type中没有被覆盖时.

但是,答案部分与线性化有关 - 我们需要覆盖Function1.toString由编译器生成的方法,如果不是由Function1以下引入的版本:

trait ProperName extends Product {
  override lazy val toString = scala.runtime.ScalaRunTime._toString(this)
}

// now just mix in ProperName and... magic!
case class Stepper(step: Int) extends (Int => Int) with ProperName {
  def apply(x:Int) = x+step
}
Run Code Online (Sandbox Code Playgroud)

然后

println(Some(2) map Stepper(2))
println(Stepper(2))
Run Code Online (Sandbox Code Playgroud)

会生产

Some(4)
Stepper(2)
Run Code Online (Sandbox Code Playgroud)

更新

这是一个ProperName不依赖于未记录的API方法的特征版本:

trait ProperName extends Product {
  override lazy val toString  = {
    val caseFields = {
       val arity = productArity
       def fields(from: Int): List[Any] =
         if (from == arity) List()
         else productElement(from) :: fields(from + 1)
       fields(0) 
    }
    caseFields.mkString(productPrefix + "(", ",", ")")
  }
}
Run Code Online (Sandbox Code Playgroud)

替代toString实现源自原始_toString方法的源代码scala.runtime.ScalaRunTime._toString.

请注意,这种替代实现仍然基于案例类总是扩展Product特征的假设.虽然后者在Scala 2.9.0中是正确的,并且是Scala社区的一些成员已知和依赖的事实,但它并未作为Scala语言规范的一部分正式记录.