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
语法糖的方式应用线性化?
这个问题与线性化无关.在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)
会生产
Run Code Online (Sandbox Code Playgroud)Some(4) Stepper(2)
更新
这是一个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语言规范的一部分正式记录.
归档时间: |
|
查看次数: |
397 次 |
最近记录: |