I am writing a wrapper to a REST web service and I'd like to have strongly typed Scala APIs.
The following is what I am doing so far:
def getMentions(count: Option[Int] = None,
sinceID: Option[TweetID] = None,
maxID: Option[TweetID] = None,
trimUser: Option[Boolean] = None,
contributorDetails: Option[Boolean] = None,
includeEntities: Option[Boolean] = None) : List[Tweet] = {
val parameters = Map("count" -> count,
"since_id" -> sinceID,
"max_id" -> maxID,
"trim_user" -> trimUser,
"contributor_details" -> contributorDetails,
"include_entities" -> includeEntities)
/*
* Convert parameters, which is a Map[String,Any] to a Map[String,String]
* (Removing Nones) and pass it to an object in charge of generating the request.
*/
...
}
This approach is working, but it requires me to manually generate the parameters
map.
If I were able to access to a Map representing parameters and their values, what I am doing would be much cleaner.
Add Elements to a Map Using the Assignment Operator in Scala We need to pass the key into the constructor and assign a value using the assignment operator. We can also use the += operator to avoid using a constructor and directly add the element to the Map.
Scala Map get() method with exampleThe get() method is utilized to give the value associated with the keys of the map. The values are returned here as an Option i.e, either in form of Some or None. Return Type: It returns the keys corresponding to the values given in the method as argument.
Per the Scaladoc, “implements immutable maps using a list-based data structure.” As shown in the examples, elements that are added are prepended to the head of the list. Keys of the map are returned in sorted order. Therefore, all traversal methods (such as foreach) return keys in that order.
Maps are classified into two types: mutable and immutable. By default Scala uses immutable Map. In order to use mutable Map, we must import scala.
You could do this with runtime reflection, and I'm sure you'll get answers telling you how, if you want that, but this is actually a neat use case for Scala 2.10's macros, so here goes. First assume we have a file named ParamMapMaker.scala
:
object ParamMapMaker {
def paramMap: Map[String, Any] = macro paramMapImpl
def paramMapImpl(c: scala.reflect.macros.Context) = {
import c.universe._
val params = c.enclosingMethod match {
case DefDef(_, _, _, ps :: Nil, _, _) =>
ps.map(p =>
reify((
c.Expr[String](Literal(Constant(p.name.decoded))).splice,
c.Expr[Any](Ident(p.symbol)).splice
)).tree
)
case _ => c.abort(c.enclosingPosition, "Can't call paramMap here!")
}
c.Expr[Map[String, Any]](Apply(Select(Ident("Map"), "apply"), params))
}
}
I'll leave snake casing the map keys as an (easy) exercise for the reader.
We also have a test file (named Test.scala
):
object Test extends App {
def foo(hello: String, answer: Int) = ParamMapMaker.paramMap
println(foo("world", 42))
}
Now we compile both of these:
scalac -language:experimental.macros ParamMapMaker.scala
scalac Test.scala
And when we run Test
we'll get the following:
Map(hello -> world, answer -> 42)
The nifty thing about this is that there's none of the overhead of runtime reflection. If we compile the test file with -Ymacro-debug-verbose
, we see that the following code has been generated (in effect) for the body of foo
at compile time:
Map.apply[String, Any](
scala.Tuple2.apply[String, String]("hello", hello),
scala.Tuple2.apply[String, Int]("answer", answer)
)
Exactly as we'd expect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With