如何编写一个函数将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()
}
}
答案 0 :(得分:3)
我认为有一种方法可以使用Manifest
,ClassTag
或TypeTag
来编写函数,因为它们只能在运行时告诉您类型。对于类似伪代码函数的工作,必须在编译时知道返回类型。
但是,可以通过定义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建议的类型类方法更安全,更具惯用性。