I want to build a function that takes as input a generic function with one argument, than parse the argument based on type and call the input function:
class PatternMatching {
val a = "test"
def test[T: TypeTag](callback: T => Unit): Unit = {
callback match {
case x if typeOf[T] <:< typeOf[String] => callback(a)
case x if typeOf[T] <:< typeOf[Array[Char]] => callback(a.toCharArray)
case _ => throw new IllegalArgumentException("error")
}
}
}
I see that type is correctly inferred but is not possible to invoke the function:
type mismatch; found : PatternMatching.this.a.type (with underlying type String) required: T case x if typeOf[T] <:< typeOf[String] => callback(a)
I understand that it's expecting a type, but I can't find a way out.
CodePudding user response:
You need explicit .asInstanceOf[T]
with the method you've written:
callback(a.asInstanceOf[T])
Though, what you're trying to achieve is typically done with typeclass in Scala. I let the reader search about it but the general idea is you would have your method defined like this:
def test[T](callback: T => Unit)(implicit converter: ConverterFromString[T]): Unit = {
callback(converter.fromString(a))
}
And there would exist in scope some values of ConverterFromString
for only some types you know how to handle.
The huge benefit of this approach is to be type-safe and if will raise errors at compile time rather than runtime if a type cannot be handled.
CodePudding user response:
Using typeclass as suggested by @Gaël J works:
trait Converter[A] {
def conveterFromString(a: String): A
}
object Converter {
implicit val stringConverter: Converter[String] = new Converter[String] {
def conveterFromString(x: String): String = x
}
implicit val arrayConverter: Converter[Array[Char]] = new Converter[Array[Char]] {
def conveterFromString(x: String): Array[Char] = x.toCharArray
}
}
class PatternMatching {
val a = "test"
def test[A](callback: A => Unit)(implicit converter: Converter[A]): Unit =
callback(converter.conveterFromString(a))
}