使用匹配大小写时保持数据类型完整

时间:2016-03-03 09:26:07

标签: scala

这会返回Any

def convertType(data: String, dataType: String) = {
  dataType match {
    case "Int" => data.toInt
    case "Double" => data.toDouble
    case "Long" => data.toLong
    case "Option[Int]" => Some(data.toInt)
    case "Option[Long]" => Some(data.toLong)
    case "Option[Double]" => Some(data.toDouble)
   }
}

// Isn't this a bad way to solve the problem ?
implicit def anyToInt(str: Any) = str.asInstanceOf[Int]
implicit def anyToLong(str: Any) = str.asInstanceOf[Long]

val i: Int = convertType("1", "Int")
val l: Long = convertType("1", "Long")

保持原始数据类型完好无损的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

  import scala.reflect.runtime.universe._

  implicit class StringConverter(data: String) {
    private[this] def convert(tag: Type): Any = tag match {
      case t if t =:= typeOf[Int] => data.toInt
      case t if t =:= typeOf[Double] => data.toDouble
      case t if t =:= typeOf[Long] => data.toLong
      case t if t =:= typeOf[Option[Int]] => Some(data.toInt)
    }
    def convert[T](implicit typeTag: TypeTag[T]): T = convert(typeTag.tpe).asInstanceOf[T]
  }
  scala> "123".convert[Int]
  res5: Int = 123

  scala> "123".convert[Option[Int]]
  res6: Option[Int] = Some(123)

  scala> "123".convert[Double]
  res7: Double = 123.0

正如@Luka Jacobowitz所说,使用generics转换类型:

  • implicit TypeTag使用通用来检索类型信息
  • Type,案例匹配以解析数据
  • asInstanceOf将变量转换为目标类型(因为它已经由TypeTag检查过,这样做是安全的)

答案 1 :(得分:0)

你想做的事情有点棘手。正如您所见,子类型不会得到您想要的东西,因为必须返回所有返回类型的超类型。

虽然输入变量,可能会节省一天!

def convertType[T](x: String): T = x.asInstanceOf[T]

但这并不是你想要的......你需要根据T传递的内容而有不同行为的东西。像(不是真正的Scala)

的东西
def convertType[T](x: String): T = T match {
  case Double => x.toDouble
  case Int => x.toInt
  // And all your other cases
}

不幸的是,Scala不是一种完全依赖类型的语言,因此我们没有可以直接对类型起作用的函数,因此匹配语句不起作用。

但是,如果我们为T类型提供了价值级别的“见证”,那么我们可以放弃转换。

def convertType[T](x: String)(witness: T): T = witness match {
  case _: Double => x.toDouble
  case _: Int => x.toInt
  // Fill in other cases as necessary
}

通过制作见证人implicit,我们可以让自己稍微方便一点。现在这只会让我们中途停留,因为我们仍然需要有奇怪的虚拟隐含值,除了作为我们函数的见证人之外什么都不做(例如随机我们需要像implicit val z = 2这样的东西)。 / p>

我们是否可以摆脱创建这些虚拟值以作为证人传递的需要?

是的,有两种方法。一种是使用Scala的TypeTags,它们恰好是编译器自动生成类型的价值级见证。

import scala.reflect.runtime.universe._

def convertTypes[T](x: String)(implicit witness: TypeTag[T]): T = witness match {
  case a if a =:= typeOf[Int] => x.toInt
  case a if a =:= typeOf[Double] => x.toDouble
}

或者,您可以将实际转换移至单独的特征,并让目击者实施特征指定的行为。

trait Convertable[T] {
  def convertFromString(x: String): T
}

implicit object ConvertInt extends Convertable[Int] {
  override def convertFromString(x: String): Int = x.toInt
}

// Do the same for your other types

def convertType[T](x: String)(implicit witness: Convertable[T]): T = witness.convertFromString(x)

然后我们去!一个很好的类型安全的转换方法(至少最后一个是)。您可能希望将整个事物包装在scala.util.Try中,以防您传递格式错误的字符串。

顺便说一下,我们刚刚重新创建了typeclasses(或者使用了Scala的内置TypeTag类型类。)