假设我想编写一个案例类Stepper
,如下所示:
case class Stepper(step: Int) {def apply(x: Int) = x + step}
它带有一个很好的toString
实现:
scala> Stepper(42).toString
res0: String = Stepper(42)
但它不是真正的功能:
scala> Some(2) map Stepper(2)
<console>:10: error: type mismatch;
found : Stepper
required: Int => ?
Some(2) map Stepper(2)
解决方法是实施Function
特征......
case class Stepper(step: Int) extends (Int => Int) {def apply(x: Int) = x + step}
但是,我不能再免费获得一个很好的toString实现了:
scala> Stepper(42).toString
res2: java.lang.String = <function1>
然后,问题是:我可以充分利用这两个世界吗?有没有一个解决方案,我有一个很好的toString
实现免费 AND trait Function
的实现。换句话说,有没有办法以最终应用case class
语法糖的方式应用线性化?
答案 0 :(得分: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
}
然后
println(Some(2) map Stepper(2))
println(Stepper(2))
将产生
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 + "(", ",", ")")
}
}
替代toString
实施源自原始_toString
方法scala.runtime.ScalaRunTime._toString
的源代码。
请注意,此替代实现仍基于假设案例类始终扩展Product
特征。虽然后者在Scala 2.9.0中是正确的,并且是Scala社区的一些成员已知和依赖的事实,但它并未正式记录为Scala Language Spec的一部分。
答案 1 :(得分:2)
编辑:覆盖toString怎么样?
case class Stepper(step: Int) extends (Int => Int) {
def apply(x: Int) = x + step
override def toString = "Stepper(" + step + ")"
}
答案 2 :(得分:1)
您可以使用隐式转换,仅在必要时将Stepper
视为函数:
case class Stepper(step: Int) { def apply(x: Int) = x + step }
implicit def s2f(s: Stepper) = new Function[Int, Int] {
def apply(x: Int) = s.apply(x)
}
现在,当您致电toString
时,您会收到案例类Stepper(42).toString
,但Some(2) map Stepper(2)
也会按照需要运作。
(请注意,为了保持机制清晰,我比上面的要求更加冗长。你也可以写implicit def s2f(s: Stepper) = s.apply _
或其他更简洁的配方。