2013-02-24 80 views
0

我正在为可以接受应用于给定数据结构的规则的系统设计接口。在运行时在Scala中检查参数类型(来自可变长度参数列表)

主系统应该作为一个驱动程序接收命令,如“将规则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

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

OR

如何转换StringInt是真的吗?

在此先感谢。


作为最低工作示例,这是斯卡拉REPL会话发源于例外:scala.Int

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) 
+0

@RexKerr其实我不知道可以直接在字符串上调用'toInt',但即使进行了更改后,仍然显示我仍然收到同样的错误。 – Jeff 2013-02-25 00:04:56

回答

2

你有盒装型(java.lang.Integer)和拆箱类型之间的不匹配( == 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])。

+0

感谢您的帮助,但我仍然不确定什么是解决我的问题的最佳方法。将'argTypes'的声明更改为使用'classOf [Integer]'而不是'classOf [Int]'? – Jeff 2013-02-25 01:11:36