user811602
user811602

Reputation: 1354

Return instance of generic type from method

I want to have a method getInstance which takes a string value and return an instance of object, defined as generic in method signature

  def getInstance[T](dataStr: String): Option[T] = {
      T match {
        case typeOf[String] => Some(dataStr)             // if type of T is String 
        case typeOf[Integer] => Some(dataStr.toInt)      // if type of T is Integer
        case typeOf[Boolean] => Some(dataStr.toBoolean)  // if type of T is Boolean
        case _ => throw new NoSuchElementException()
      }
  }

How can I write same in Scala?

Scala version: 2.11

Upvotes: 2

Views: 78

Answers (3)

I believe you are trying to use the Scala's ClassTag.

import scala.reflect.{ClassTag, classTag}
import scala.util.Try

def getInstance[T](dataStr: String)(implicit T: ClassTag[T]): Option[T] = T match {
  case _ if T == classTag[String]  => Some(dataStr).flatMap(T.unapply)
  case _ if T == classTag[Int]     => Try(dataStr.toInt).toOption.flatMap(T.unapply)
  case _ if T == classTag[Long]    => Try(dataStr.toLong).toOption.flatMap(T.unapply)
  case _ if T == classTag[Float]   => Try(dataStr.toFloat).toOption.flatMap(T.unapply)
  case _ if T == classTag[Double]  => Try(dataStr.toDouble).toOption.flatMap(T.unapply)
  case _ if T == classTag[Boolean] => Try(dataStr.toBoolean).toOption.flatMap(T.unapply)
  case _                           => None
}

Upvotes: 1

Tim
Tim

Reputation: 27421

A typeclass is probably the best solution.

trait FromString[T] {
  def apply(s: String): T
}

object FromString {
  implicit object IntString extends FromString[Int] {
    def apply(s: String) = s.toInt
  }
  implicit object DoubleString extends FromString[Double] {
    def apply(s: String) = s.toDouble
  }
  implicit object BooleanString extends FromString[Boolean] {
    def apply(s: String) = s.toBoolean
  }
}

def getInstance[T](dataStr: String)(implicit from: FromString[T]): Option[T] =
  Some(from(dataStr))

val a = getInstance[Int]("1")
val b = getInstance[Double]("1.0")
val c = getInstance[Boolean]("true")

This will give compile-time checking of valid types for getInstance and will return the appropriate Option type.

Upvotes: 5

Chaitanya
Chaitanya

Reputation: 3638

You can use pattern matching in scala which solves the problem elegantly.

   def getInstance[T >: Any](dataStr: String, myType : T) : Option[T] ={
  myType match {
    case x @ Int => Option(dataStr.toInt)
    case x @ Double => Option(dataStr.toDouble)
    case x @ Float => Option(dataStr.toFloat)
    case _ => throw new NoSuchElementException()
  }
}

On invoking the function,

getInstance("1",Int)
getInstance("1",Double)
getInstance("1",Float)

will give you result as

res0: Option[Any] = Some(1)
res1: Option[Any] = Some(1.0)
res2: Option[Any] = Some(1.0)

Upvotes: 2

Related Questions