从String函数转换Scala泛型

时间:2015-06-03 18:09:38

标签: scala generics casting

如何编写一个函数将String转换为泛型类型(Double,Int,Float等)?

这是我正在寻找的功能的伪代码:

def castFromString[A: Manifest](value: String): A = {
  if (A == Double) {
    parseDouble(value)
  } else if (A == Int) {
    parseInt(value)
  } else {
    value.toString()
  }
}

3 个答案:

答案 0 :(得分:3)

我认为有一种方法可以使用ManifestClassTagTypeTag来编写函数,因为它们只能在运行时告诉您类型。对于类似伪代码函数的工作,必须在编译时知道返回类型。

但是,可以通过定义type class并为要转换的类型编写实例来实现该功能。这是一个例子:

import java.lang.Double.parseDouble
import java.lang.Integer.parseInt

trait CastableFromString[A] {
  def fromString(string: String): A
}

object CastableFromString {
  implicit object DoubleCastableFromString extends CastableFromString[Double] {
    override def fromString(string: String): Double =
      parseDouble(string)
  }

  implicit object IntCastableFromString extends CastableFromString[Int] {
    override def fromString(string: String): Int =
      parseInt(string)
  }

  implicit object IntListCastableFromString extends CastableFromString[List[Int]] {
    override def fromString(string: String): List[Int] =
      string.split(',').map(parseInt).toList
  }

  def castFromString[A](string: String)(implicit cast: CastableFromString[A]): A =
    cast.fromString(string)
}

object Main {
  import CastableFromString._

  def main(args: Array[String]): Unit = {
    val d = castFromString[Double]("4.5")
    val i = castFromString[Int]("42")
    val li = castFromString[List[Int]]("1,2,3")
    println(s"d=$d i=$i li=$li")
  }
}

或者,为了更接近类似于您的伪代码的东西,您可以使用macro。这是一个例子(不适用于比Scala 2.11更早的版本):

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context

class StringCasterImpl(val c: Context) {
  def castFromStringImpl[A: c.WeakTypeTag](string: c.Expr[String]): c.Tree = {
    import c.universe._
    val t = c.weakTypeOf[A]
    if (t =:= typeOf[Double]) {
      q"java.lang.Double.parseDouble($string)"
    } else if (t =:= typeOf[Int]) {
      q"java.lang.Integer.parseInt($string)"
    } else if (t =:= typeOf[List[Int]]) {
      q"$string.split(',').map(java.lang.Integer.parseInt).toList"
    } else {
      c.abort(c.enclosingPosition, s"Don't know how to cast $t to String")
    }
  }
}

object StringCaster {
  def castFromString[A](string: String): A =
    macro StringCasterImpl.castFromStringImpl[A]
}

// note that this object must be in a separate compilation unit
object Main {
  import StringCaster._

  def main(args: Array[String]): Unit = {
    val d = castFromString[Double]("4.2")
    val i = castFromString[Int]("42")
    val li = castFromString[List[Int]]("1,2,3")
    println(s"d=$d i=$i li=$li")
  }
}

答案 1 :(得分:0)

您可以定义将字符串转换为特定类型的隐式函数。

然后在需要时它将自动进行铸造。

math.max(1,"3") // throws error

但现在

implicit def StringToInt(x: String): Int = x

math.max(1,"3")  //>> 3

答案 2 :(得分:0)

如果您想这样做,可以匹配runtimeClass中的ClassTag

def castFromString[A: ClassTag](value: String): A = {
  val c = implicitly[ClassTag[A]].runtimeClass
  if(c == classOf[Double]) parseDouble(value).asInstanceOf[A]
  else ...
}

请注意需要asInstanceOf演员表。 @Olli建议的类型类方法更安全,更具惯用性。