Reputation: 41
I just want to overload seq in a function, like:
insertBatch(sql: String, params: Seq[Seq[String]])
insertBatch(sql: String, params: Seq[Map[String,String]])
But always hint me that "insertBatch(String, Seq) is already defined in scope". So I try to use "Any":
insertBatch(sql: String, params: Seq[Any])
This can be defined, but how can I use this params in the function? such as:
def insertBatch(sql: String, params: Seq[Any]){
......
for( param <- params) {
// when param is a map?
for( p <- param) {
...
}
// when param is a seq?
param.get("some Key")
...
}
......
}
Scala is just a new language for me, Any help?
Upvotes: 4
Views: 1721
Reputation: 14825
Because of the type erasure of the JVM the above two methods are indistinguishable by the JVM at runtime. The general way to deal with type erasure issues is TypeTag
. You may use classTag
as well but classTag
is limited.
So, Instead of declaring two methods, declare one method with type parameter T
and at runtime figure out what T
is and proceed.
import scala.reflect.runtime.universe._
def insertBatch[T: TypeTag](sql: String, params: Seq[T]): Unit = typeOf[T] match {
case a if a =:= typeOf[Seq[String]] =>
val l = params.asInstanceOf[Seq[Seq[String]]]
// do something here
case b if b =:= typeOf[Map[String, String]] =>
val l = params.asInstanceOf[Seq[Map[String, String]]]
// do something here
case _ => //some other types
}
Scala REPL
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.reflect.runtime.universe._
def insertBatch[T: TypeTag](sql: String, params: Seq[T]): Unit = typeOf[T] match {
case a if a =:= typeOf[Seq[String]] =>
val l = params.asInstanceOf[Seq[Seq[String]]]
println("bar")
case b if b =:= typeOf[Map[String, String]] =>
val l = params.asInstanceOf[Seq[Map[String, String]]]
println("foo")
case _ => println("ignore")
}
// Exiting paste mode, now interpreting.
import scala.reflect.runtime.universe._
insertBatch: [T](sql: String, params: Seq[T])(implicit evidence$1: reflect.runtime.universe.TypeTag[T])Unit
scala> insertBatch[Seq[String]]("", Seq(Seq("")))
bar
scala> insertBatch[Map[String, String]]("", Seq(Map.empty[String, String]))
foo
scala> insertBatch[String]("", Seq(""))
ignore
Upvotes: 2
Reputation:
You should use a discriminated union instead of Any
, for example:
def insertBatch[T](sql: String, params: Seq[Either[Seq[String], Map[String, String]]]) =
params foreach {
case Left(seq) => ...
case Right(map) => ...
}
This makes clear your intent in the type, doesn't suffer from type erasure issues, and doesn't violate parametricity.
Upvotes: 0
Reputation: 13985
The thing is that all type parameters
are erased at runtime (type erasure
) hence type parameters
are ignored ored for determining the signature of a method.
Now lets comeback to your requirement, you want your function to behave differently for Seq[Seq[String]]
and Seq[Map[String,String]]
. You will have to change it in a way so that the "type hint" is included by the compiler.
def insertBatch[T](sql: String, params: Seq[T]){
for( param <- params) {
param match {
// when param is a map?
case _: Map[_, _] => for(key <- param.keys) {
...
}
// when param is a seq?
case _: Seq[_] => for( p <- param) {
...
}
}
}
}
Upvotes: 0