【问题标题】:Check argument type (from a variable length argument list) at runtime in Scala在 Scala 运行时检查参数类型(来自可变长度参数列表)
【发布时间】:2013-02-24 22:36:09
【问题描述】:

我正在为一个系统设计接口,该系统可以接受应用于给定数据结构的规则。

主系统应该作为接收命令的驱动程序工作,例如“将规则 X 应用于参数 U、V、W,...”。我在编译时不知道所有可能的规则,所以我想将参数类型信息嵌入到规则定义中并稍后验证。

目前规则定义如下:

trait Rule {
  val argTypes: Seq[Class[_]]
  def apply(stt: State, args: Seq[Any])
}

args 中实际参数的数量必须与argTypes 中定义的类型数量相匹配,并且apply 方法应该返回一个操作状态。 (其实这是简化的解释,但这是大意)。

我还实现了一个名为checkTypes 的函数来验证实际参数的类型是否与argTypes 中定义的类型匹配。

def checkTypes(args: Seq[Any]) {
  if (argTypes.size != args.size) {
    val msg = "Number of arguments (%d) does not match expected number (%d)."
    throw new IllegalArgumentException(msg.format(args.size, argTypes.size))
  }
  val err = "Incompatible argument type for [%s]. Expected: %s. Found: %s."
  for (i <- 0 until argTypes.size) {
    val formalClass = argTypes(i)
    val arg = args(i)
    val actualClass = arg.asInstanceOf[AnyRef].getClass
    if (!(formalClass isAssignableFrom actualClass)) {
      val errMsg = err.format(arg, formalClass.getName, actualClass.getName)
      throw new IllegalArgumentException(errMsg)
    }
  }
}

问题在于,每当我尝试传递整数参数(从控制台或文本文件读取)时,checkTypes 过程都会失败并显示以下消息:java.lang.IllegalArgumentException: Incompatible argument type for [1]. Expected: int. Found: java.lang.Integer.

我正在用Integer.parseInt(t).asInstanceOf[Int] 转换整数参数,并且规则需要两个Int 类型的参数

那么,有没有更有效的方法在运行时检查参数类型?

如何将String 真正转换为Int

提前致谢。


作为一个最小的工作示例,这是 Scala REPL 中引发异常的会话:

scala> val argTypes: Seq[Class[_]] = Seq(classOf[Int], classOf[Int])
argTypes: Seq[Class[_]] = List(int, int)

scala> def checkTypes(args: Seq[Any]) {
     |   if (argTypes.size != args.size) {
     |     val msg = "Number of arguments (%d) does not match expected number (%d)."
     |     throw new IllegalArgumentException(msg.format(args.size, argTypes.size))
     |   }
     |   val err = "Incompatible argument type for [%s]. Expected: %s. Found: %s."
     |   for (i <- 0 until argTypes.size) {
     |     val formalClass = argTypes(i)
     |     val arg = args(i)
     |     val actualClass = arg.asInstanceOf[AnyRef].getClass
     |     if (!(formalClass isAssignableFrom actualClass)) {
     |       val errMsg = err.format(arg, formalClass.getName, actualClass.getName)
     |       throw new IllegalArgumentException(errMsg)
     |     }
     |   }
     | }
checkTypes: (args: Seq[Any])Unit

scala> val args: Seq[Any] = Seq("1".toInt, "2".toInt)
args: Seq[Any] = List(1, 2)

scala> checkTypes(args)
java.lang.IllegalArgumentException: Incompatible argument type for [1]. Expected: int. Found: java.lang.Integer.
    at $anonfun$checkTypes$1.apply$mcVI$sp(<console>:20)
    at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:78)
    at .checkTypes(<console>:14)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
    at java.lang.Thread.run(Thread.java:679)

【问题讨论】:

  • @RexKerr 实际上我不知道可以直接在字符串上调用toInt,但即使在进行了您建议的更改之后,我仍然会遇到同样的错误。

标签: scala variadic-functions runtime-type


【解决方案1】:

装箱类型 (java.lang.Integer) 和未装箱类型 (scala.Int == java int) 不匹配。实际实例是装箱的,但您正在针对原始 classOf 对其进行测试。

以下是原语被装箱时发生的情况的示例:

scala> 5.getClass
res0: Class[Int] = int

scala> (5: Any)
res1: Any = 5

scala> res1.getClass
res2: Class[_] = class java.lang.Integer

请注意,如果您在 Any 上进行模式匹配并获得一个原语,它实际上会挑选出装箱的副本并为您拆箱。

scala> res1 match { case i: Int => println(i); case _ => }
5

既然您知道您必须被装箱,鉴于您编写的代码,您不妨只检查Integer 而不是Int(即使用classOf[Integer])。

【讨论】:

  • 感谢您的帮助,但我仍然不确定解决问题的最佳方法是什么。将argTypes 的声明更改为使用classOf[Integer] 而不是classOf[Int]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-09-22
  • 1970-01-01
相关资源
最近更新 更多