Scala - how to print case classes like (pretty printed) tree

前端 未结 10 1846
情歌与酒
情歌与酒 2020-12-07 22:35

I\'m making a parser with Scala Combinators. It is awesome. What I end up with is a long list of entagled case classes, like: ClassDecl(Complex,List(VarDecl(Real,float

10条回答
  •  抹茶落季
    2020-12-07 23:05

    Starting Scala 2.13, case classes (which are an implementation of Product) are now provided with a productElementNames method which returns an iterator over their field's names.

    Combined with Product::productIterator which provides the values of a case class, we have a simple way to pretty print case classes without requiring reflection:

    def pprint(obj: Any, depth: Int = 0, paramName: Option[String] = None): Unit = {
    
      val indent = "  " * depth
      val prettyName = paramName.fold("")(x => s"$x: ")
      val ptype = obj match { case _: Iterable[Any] => "" case obj: Product => obj.productPrefix case _ => obj.toString }
    
      println(s"$indent$prettyName$ptype")
    
      obj match {
        case seq: Iterable[Any] =>
          seq.foreach(pprint(_, depth + 1))
        case obj: Product =>
          (obj.productIterator zip obj.productElementNames)
            .foreach { case (subObj, paramName) => pprint(subObj, depth + 1, Some(paramName)) }
        case _ =>
      }
    }
    

    which for your specific scenario:

    // sealed trait Kind
    // case object Complex extends Kind
    // case class VarDecl(a: Int, b: String)
    // case class ClassDecl(kind: Kind, decls: List[VarDecl])
    
    val data = ClassDecl(Complex, List(VarDecl(1, "abcd"), VarDecl(2, "efgh")))
    
    pprint(data)
    

    produces:

    ClassDecl
      kind: Complex
      decls: 
        VarDecl
          a: 1
          b: abcd
        VarDecl
          a: 2
          b: efgh
    

提交回复
热议问题