2

Dynamic次のように、scala 2.10.0-RC1 から変数を追加します。

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、コンパイラはそれが type であると考えているため、機能しませんAny

しかし、それはまたMain.figname.isInstanceOf[Figure] == trueAnyあり、 ですが、能力Figureはありません。Figures今、私はそれをキャストすることができMain.figname.asInstanceOf[Figure].number、それはうまくいきます! これは醜いです!また、これをドメイン ユーザーに提示することはできません (内部 DSL を構築したいと考えています)。

注:Anyスーパータイプの代わりに使用Figureしても機能しません。

これは scala 2.10 のバグですか、それとも機能ですか?

4

2 に答える 2

2

それは非常に論理的です。のインスタンスを明示的に返しています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
于 2012-11-06T16:45:23.833 に答える
0

Anyまたは任意の定義済みに拡張機能またはカスタム機能を追加できますvalue classes。次のように暗黙の値クラスを定義できます。

  implicit class CustomAny(val self: Any) extends AnyVal {
    def as[T] = self.asInstanceOf[T]
  }

使用法:

scala> class Figure {
     | val xyz = "xyz"
     | }
defined class Figure
scala> val fig = new Figure()
fig: Figure = Figure@73dce0e6

scala> Main.figname = fig
Main.figname: Any = Figure@73dce0e6

scala> Main.figname.as[Figure].xyz
res8: String = xyz

暗黙的な値のクラスは、通常のクラスのようにコストがかかりません。これはコンパイル時に最適化され、新しくインスタンス化されたオブジェクトのメソッド呼び出しではなく、静的オブジェクトのメソッド呼び出しと同等になります。

暗黙の値クラスの詳細については、こちらを参照してください。

于 2015-08-05T06:10:35.680 に答える