Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Iteration over case class fields

I'm trying to write a generic method to iterate over a case class's fields :

case class PriceMove(price: Double, delta: Double)

def log(pm : PriceMove) { info("price -> " + price + " delta -> " + delta)}

I need to make log able to handle any case class. What needs to be the argument type for log to handle case classes only and the actual generic field iteration code?

like image 244
212 Avatar asked Apr 17 '14 08:04

212


People also ask

What is the difference between Case class and class in Scala?

A class can extend another class, whereas a case class can not extend another case class (because it would not be possible to correctly implement their equality).

Can case class have methods?

Case Classes You can construct them without using new. case classes automatically have equality and nice toString methods based on the constructor arguments. case classes can have methods just like normal classes.

What is the purpose of case class in Scala?

The one of the topmost benefit of Case Class is that Scala Compiler affix a method with the name of the class having identical number of parameters as defined in the class definition, because of that you can create objects of the Case Class even in the absence of the keyword new.

Is Scala case class immutable?

A Scala Case Class is like a regular class, except it is good for modeling immutable data. It also serves useful in pattern matching, such a class has a default apply() method which handles object construction. A scala case class also has all vals, which means they are immutable.


2 Answers

Okay, considering the two questions I attached to the question, here is what I'd use:

object Implicits {
  implicit class CaseClassToString(c: AnyRef) {
    def toStringWithFields: String = {
      val fields = (Map[String, Any]() /: c.getClass.getDeclaredFields) { (a, f) =>
        f.setAccessible(true)
        a + (f.getName -> f.get(c))
      }

      s"${c.getClass.getName}(${fields.mkString(", ")})"
    }
  }
}

case class PriceMove(price: Double, delta: Double)

object Test extends App {
  import Implicits._
  println(PriceMove(1.23, 2.56).toStringWithFields)
}

This produces:

PriceMove(price -> 1.23, delta -> 2.56)
like image 139
serejja Avatar answered Oct 02 '22 08:10

serejja


I'm afraid there is no easy way to achieve what you're after, as you can't easily get the field names from the case class as discussed here: Reflection on a Scala case class and Generic customisation of case class ToString.

You can try using reflection (though you can guarantee the order of the fields) or tools.nsc.interpreter.ProductCompletion, but both solutions are significantly more complex then you'd really expect.

like image 40
Norbert Radyk Avatar answered Oct 02 '22 09:10

Norbert Radyk