我想做这样的事情:
implicit class MyString(s: String) {
def getAs[T]: T = {
T match {
case q if q == classOf[Int] => s.toInt
case q if q == classOf[Boolean] => s.toBoolean
}
}
}
当然,这不会编译。我怎么写这个呢?
答案 0 :(得分:4)
考虑这种方法:
object Parse {
def parse[T](f:String => Option[T]) = f
implicit val parseInt = parse(s => Try(s.toInt).toOption)
implicit val parseLong = parse(s => Try(s.toLong).toOption)
implicit val parseDouble = parse(s => Try(s.toDouble).toOption)
implicit val parseBoolean = parse(s => Try(s.toBoolean).toOption)
}
implicit class MyString(s:String) {
def getAs[T]()(implicit run: String => Option[T]): Option[T] = run(s)
}
用法:
def main(args: Array[String]) {
import Parse._
"true".getAs[Boolean].foreach(println)
"12345".getAs[Int].foreach(println)
}
答案 1 :(得分:2)
当使用 classOf 进行类型匹配时,可能会遇到一些问题,例如:
scala> classOf[List[Int]] == classOf[List[String]]
res17: Boolean = true
scala> typeOf[List[Int]] =:= typeOf[List[String]]
res18: Boolean = false
classOf
仅存储不使用泛型类型
typeOf
将存储完整类型信息
class MyString(s: String) {
def getAs[T](implicit tag: TypeTag[T]): T = {
tag.tpe match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
}
}
}
scala> new MyString("123")
res2: MyString = MyString@7fca02
scala> res6.getAs[Int]
res3: Int = 123
使用TypeType
标记获取类型信息,并使用类型信息调用getAs
。
答案 2 :(得分:1)
这是我到目前为止所提出的:
import reflect.runtime.universe.TypeTag
import scala.reflection.runtime.universe._
implicit class MyString(s: String) {
def getAs[T : TypeTag]: T = {
typeOf[T] match {
case t if t =:= typeOf[Int] => s.toInt.asInstanceOf[T]
case t if t =:= typeOf[Boolean] => s.toBoolean.asInstanceOf[T]
}
}
}
在REPL中运行:
scala> "32".getAs[Int]
res25: Int = 32
scala> "32".getAs[Boolean]
java.lang.IllegalArgumentException: For input string: "32"
at scala.collection.immutable.StringLike$class.parseBoolean(StringLike.scala:290)
at scala.collection.immutable.StringLike$class.toBoolean(StringLike.scala:260)
at scala.collection.immutable.StringOps.toBoolean(StringOps.scala:30)
at MyString.getAs(<console>:33)
... 43 elided
scala> "false".getAs[Int]
java.lang.NumberFormatException: For input string: "false"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
at scala.collection.immutable.StringOps.toInt(StringOps.scala:30)
at MyString.getAs(<console>:32)
... 43 elided
scala> "false".getAs[Boolean]
res28: Boolean = false
scala> "false".getAs[String]
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
at MyString.getAs(<console>:31)
... 43 elided
我认为更好的方法是返回option[T]
,并捕获任何未满足的问题,例如类型T
,或尝试失败的演员表。我开始使用scala的Try
(以及它的.toOption
方法),但是遇到了一些奇怪的错误,所以还没有进一步说明。
编辑:只需使用简单的try-catch,我们就可以获得:
implicit class MyString(s: String) {
def getAs[T : TypeTag]: Option[T] = try {
typeOf[T] match {
case t if t =:= typeOf[Int] => Some(s.toInt.asInstanceOf[T])
case t if t =:= typeOf[Boolean] => Some(s.toBoolean.asInstanceOf[T])
}
} catch {
case ex: Exception => None
}
}
导致:
scala> "false".getAs[String]
res30: Option[String] = None
scala> "32".getAs[Boolean]
res31: Option[Boolean] = None
scala> "32".getAs[Int]
res32: Option[Int] = Some(32)
scala> "true".getAs[Boolean]
res33: Option[Boolean] = Some(true)
scala> "true".getAs[Int]
res34: Option[Int] = None
答案 3 :(得分:0)
基于@chengpohi和@Shadowlands给出的答案,这就是我想出来的。
object ImplicitsStartingWithS {
implicit class MyString(s: String) {
val str = s.trim
import reflect.runtime.universe.TypeTag
import scala.reflect.runtime.universe._
def getAs[T](implicit tag: TypeTag[T]): Option[T] = {
val value = tag.tpe match {
case t if t =:= typeOf[Int] => str.toIntStr.map(_.toInt)
case t if t =:= typeOf[Long] => str.toIntStr.map(_.toLong)
case t if t =:= typeOf[Float] => str.toNumericStr.map(_.toFloat)
case t if t =:= typeOf[Double] => str.toNumericStr.map(_.toDouble)
case _ => None
}
value.asInstanceOf[Option[T]]
}
def toDecimalStr = "^-*\\d+\\.\\d+$".r.findFirstIn(s)
def toIntStr = "^-*\\d+$".r.findFirstIn(s)
def toNumericStr = {
s.toDecimalStr match {
case Some(decimalStr) => Some(decimalStr)
case None => s.toIntStr
}
}
}
}
这可以避免异常处理以加快响应速度。