如何在Scala中匹配函数的类型参数

如何在Scala中匹配函数的类型参数,scala,pattern-matching,Scala,Pattern Matching,我想这样做: 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 } } } 当然,这不会编译。我该如何编写它呢?当使用classOf进行类型匹配时,可能会出现一些问题,例如: sca

我想这样做:

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
    }
  }
}

当然,这不会编译。我该如何编写它呢?

当使用classOf进行类型匹配时,可能会出现一些问题,例如:

scala> classOf[List[Int]] == classOf[List[String]]
res17: Boolean = true
scala> typeOf[List[Int]] =:= typeOf[List[String]]
res18: Boolean = false
classOf
仅存储类信息,不使用泛型类型

typeOf
将存储完整的类型信息


使用
TypeType
标记获取类型信息,并使用类型信息调用
getAs

这就是我到目前为止的想法:

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
导致:

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

根据@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
      }
    }
  }
}

这避免了异常处理以获得更快的响应。

请考虑以下方法:

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)
}

什么是
tag.tpe
?在带有Ctrl+F的文档中找不到它。
tpe
TypeTag
的方法,用于获取类型
type
(标记)。而且
tpe
类型很好,我尝试在另一个方法中使用
getAs[T]
方法,该方法有一个类型参数,结果是:
没有可用于T
的TypeTag。看起来这是不可能的。如果可能的话,我建议用尼亚夫罗的方法来代替。尼亚夫罗的答案是正常的Scala代码;这种类型标签的东西是不寻常的,应该被视为最后的手段。另外,您是否实际测试过正则表达式处理比异常更快?我对此持怀疑态度。我相信这个有用的堆栈溢出将解决您的问题。
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)
}