Scala: переопределить toString, чтобы кавычки печатались вокруг строк

Я хотел бы написать функцию "toSource", которая будет генерировать исходный код для базовых классов. Например, я хотел бы:

case class Person(name: String, age: Int)
val bob = Person("Bob", 20)
println(toSource(bob)) // Should print """Person("Bob", 20)"""

Функция "toString" почти дает мне то, что я хочу, но она сбрасывает кавычки вокруг строк:

println(bob.toString) // Prints """Person(Bob, 20)"""

Есть идеи, как это сделать?

2 ответа

Решение

Вы можете использовать тот факт, что тематические классы смешиваются в чертах Product:

def toSource(p: Product): String =
   p.productIterator.map {
      case s: String => "\"" + s + "\""
      case other => other.toString
   } mkString (p.productPrefix + "(", ", ", ")")

toSource(Person("Bob", 20))  // yields """Person("Bob", 20)"""

Опираясь на решение, предоставленное0__, я написал этот подход, который работает с классами, которые используют только несколько примитивных типов:

      object Main {

  def toSourcePrimitive(l: Long): String =
    l.toString + "L"

  def toSourcePrimitive(i: Int): String =
    i.toString

  def toSourcePrimitive(s: String): String =
    "\"" + s.replace("\"", "\\\"") + "\""

  def toSourcePrimitive[T](li: List[T]): String = 
    "List(" + li.map(toSource).mkString(", ") + ")"

  def toSourcePrimitive[T](op: Option[T]): String = 
    if (op.isEmpty) "None" else "Some(" + toSource(op.get) + ")"

  def toSourcePrimitive(p: Product): String = {
    p.productIterator.map(toSource).mkString(p.productPrefix + "(", ", ", ")")
  }

  def toSource(a: Any): String = a match {
    case in: Int       => toSourcePrimitive(in)
    case ln: Long      => toSourcePrimitive(ln)
    case s: String     => toSourcePrimitive(s)
    case li: List[_]   => toSourcePrimitive(li)
    case op: Option[_] => toSourcePrimitive(op)
    case p: Product    => toSourcePrimitive(p)
    case _             => "ERROR"
  }

  case class Example1(date: Int, numLong: Long, numInt: Int)

  case class Example2(v1: String, v2: List[String], v3: List[Example1], v4: Option[String])
  
  def main(args: Array[String]): Unit = {
    println("\nExample 1:")
    println(toSource(Example1(20220105, 6L, 10)))

    println("\nExample 2:")
    val elems = List(
      Example2("blah", List("one", "two"), List(Example1(20220105, 6L, 10)), Some("three")),
      Example2("blah", Nil, List(Example1(20220105, 6L, 10)), None)
    )
    println(toSource(elems))    
  }
}

Результат показан ниже:

      Example 1:
Example1(20220105, 6L, 10)

Example 2:
List(Example2("blah", List("one", "two"), List(Example1(20220105, 6L, 10)), Some("three")), Example2("blah", List(), List(Example1(20220105, 6L, 10)), None))
Другие вопросы по тегам