scala - 避免对 scala 的动态类型进行显式强制转换

标签 scala

我从 scala 2.10.0-RC1 添加带有 Dynamic 的变量,如下所示:

import language.dynamics
import scala.collection.mutable.HashMap

object Main extends Dynamic {
  private val map = new HashMap[String, Any]
  def selectDynamic(name: String): Any = {return map(name)}
  def updateDynamic(name:String)(value: Any) = {map(name) = value}
}

val fig = new Figure(...)  // has a method number

Main.figname = fig

现在,如果我想访问 Main.figname.number 它不起作用,因为编译器认为它是 Any 类型。

但它也是 Main.figname.isInstanceOf[Figure] == true,所以它是 AnyFigure,但没有数字能力。现在我可以将其转换为 Main.figname.asInstanceOf[Figure].number 并且它可以工作!这太丑了!我无法将其呈现给我的域用户(我想构建一个内部 DSL。)

注意:如果我使用 Figure 的父类(super class)型而不是 Any,它也不起作用。

这是 scala 2.10 中的错误还是功能?

最佳答案

这是非常符合逻辑的。您显式返回 Any 的实例。解决方法是始终使用 Dynamic 实例:

import language.dynamics
import scala.collection.mutable.HashMap
import scala.reflect.ClassTag

trait DynamicBase extends Dynamic {
  def as[T:ClassTag]: T
  def selectDynamic[T](name: String): DynamicBase
  def updateDynamic(name:String)(value: Any)
}

class ReflectionDynamic( val self: Any ) extends DynamicBase with Proxy {
  def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( self ) }
   // TODO: cache method lookup for faster access + handle NoSuchMethodError
  def selectDynamic[T](name: String): DynamicBase = {
    val ref = self.asInstanceOf[AnyRef]
    val clazz = ref.getClass
    clazz.getMethod(name).invoke( ref ) match {
      case dyn: DynamicBase => dyn
      case res => new ReflectionDynamic( res )
    }
  }
  def updateDynamic( name: String )( value: Any ) = {
    val ref = self.asInstanceOf[AnyRef]
    val clazz = ref.getClass
    // FIXME: check parameter type, and handle overloads
    clazz.getMethods.find(_.getName == name+"_=").foreach{ meth =>
      meth.invoke( ref, value.asInstanceOf[AnyRef] )
    }
  }
}

object Main extends DynamicBase {  
  def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( this ) }
  private val map = new HashMap[String, DynamicBase]
  def selectDynamic[T](name: String): DynamicBase = { map(name) }
  def updateDynamic(name:String)(value: Any) = {
    val dyn = value match {
      case dyn: DynamicBase => dyn
      case _ => new ReflectionDynamic( value )
    }
    map(name) = dyn
  }
}

用法:

scala>     class Figure {
     |       val bla: String = "BLA"
     |     }
defined class Figure
scala> val fig = new Figure()  // has a method number
fig: Figure = Figure@6d1fa2
scala> Main.figname = fig
Main.figname: DynamicBase = Figure@6d1fa2
scala> Main.figname.bla
res40: DynamicBase = BLA

所有实例都包装在动态实例中。 我们可以使用执行动态转换的 as 方法恢复实际类型。

scala> val myString: String = Main.figname.bla.as[String]
myString: String = BLA

关于scala - 避免对 scala 的动态类型进行显式强制转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13253557/

相关文章:

python - scala:具有可变长度参数的函数对象的特征?

scala - 缓存 Slick DBIO 操作

scala - 在 Play 中启动 Akka Actor

scala - Haskell 序列的模拟

generics - 在 Scala 中创建参数图类型

mysql - PlayFramework Slick NoSuchMethodError

scala - 为什么(复制)附加到 Scala 中的 Seq 被定义为 :+ and not just + as in Set and Map?

scala - 在子项目中打开 sbt

multithreading - 为什么 Scala 使用 ForkJoinPool 来支持其默认的 ExecutionContext?

scala - 比较scala中的==字符