我正在为一个系统设计接口,该系统可以接受应用于给定数据结构的规则。
主系统应该是一个接收命令的驱动程序,比如"将规则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)
装箱类型(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]
)。