2013-02-24 61 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

相關問題