Вопрос не имеет отношения к линеаризации.В case-классах toString
- это метод, автоматически генерируемый компилятором, если и только если Any.toString
не переопределяется в типе конца.
Однако ответ частично связан с линеаризацией - нам нужно переопределить 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
.
Обратите внимание, что эта альтернативная реализация по-прежнему основана на предположении, что класс case всегда расширяет черту Product
.Хотя последнее относится к Scala 2.9.0 и является фактом, который известен и на который полагаются некоторые члены сообщества Scala, он официально не задокументирован как часть Scala Language Spec .