我有一个函数,应该用它的值查找命令行参数,然后将其返回转换为类型P
:
def parameter[P](name: String)(implicit tag: ClassTag[P]): P = {
val paramName = s"--$name"
args.sliding(2, 2).toList.collectFirst {
case Array(`paramName`, param: String) => {
// if P is Int => param.toInt
// if P is Double => param.toDouble
}
}.get
}
我该怎么做?我发现ClassTag
是一种解决方法,但是在这种情况下却无法弄清楚如何使用它。
答案 0 :(得分:5)
您可以将class标签与要匹配的类型的标签进行比较:
import scala.reflect.{ClassTag, classTag}
def parameter[P](args: Array[String], name: String)(implicit tag: ClassTag[P]): P = {
val paramName = s"--$name"
args.sliding(2, 2).toList.collectFirst {
case Array(`paramName`, param: String) => (
if (tag == classTag[Double]) {
param.toDouble
} else if (tag == classTag[Int]) {
param.toInt
} // and so on...
).asInstanceOf[P]
}.get
}
您当然也可以使用模式匹配。它按预期工作:
scala> parameter[Int](Array("--foo", "123"), "foo")
res0: Int = 123
scala> parameter[Double](Array("--foo", "123"), "foo")
res1: Double = 123.0
但是,这种方法有很多缺点-您必须了解parameter
的定义中要解析的所有类型,等等-最好使用合适的类型类专为您正在执行的解析而设计。
答案 1 :(得分:1)
很少有资源可以帮助您:
链接之一中的示例:
scala> val StringClass = classTag[String]
scala> val IntClass = classTag[Int]
scala> def typeList[T](list: List[T])(implicit tag: ClassTag[T]) =
tag match {
case StringClass => "It's a String!"
case IntClass => "It's an Integer."
case _ => "It's something else entirely"
}
答案 2 :(得分:1)
所以Travis'和ColOfAbRiX's的答案是可行的解决方案。但是正如Travis指出的那样,它们不是 typesafe 。
这是我最终得到的解决方案(请参见Scala Type Classes 101: Introduction)
为所需类型定义隐式转换器:
trait StringConverter[P] {
def convert(a: String): P
}
implicit val string2string = new StringConverter[String] {
def convert(a: String): String = a
}
implicit val string2double = new StringConverter[Double] {
def convert(a: String): Double = a.toDouble
}
implicit val string2int = new StringConverter[Int] {
def convert(a: String): Int = a.toInt
}
implicit val string2long = new StringConverter[Long] {
def convert(a: String): Long = a.toLong
}
implicit val string2bool = new StringConverter[Boolean] {
def convert(a: String): Boolean = a.toBoolean
}
然后按如下所示使用它们:
def parameter[P](name: String)(implicit converter: StringConverter[P]): P = {
val paramName = s"--$name"
val res = args.sliding(2, 2).toList.collectFirst {
case Array(`paramName`, param: String) => converter.convert(param)
}
res.get
}
按原样接受(IMHO)更加干净和类型安全-如果您未为使用的一种或多种类型定义转换,则它将无法编译(ClassTag
解决方案将在运行时编译并失败)。
评论,更正,建议非常感激。