给定一个对象,我如何实例化一个类相同的新对象加上一个额外的特征

时间:2014-01-21 07:10:47

标签: scala reflection traits

如果我有一些对象x,并且我想创建一个与x具有相同类别的新实例,我可以说:

x.getClass.newInstance

如果x属于某个(未知)类T,则新实例也属于T类。

但实际上我想创建一个T with A的新实例。换句话说,我想做类似的事情:

(x.getClass with A).newInstance

但这不起作用。有可能这样做吗?

2 个答案:

答案 0 :(得分:2)

首先,您不能只是向现有类添加特征或接口,因为JVM类是静态的 - 您必须创建两者的子类。但是你不能动态创建类而不用手动摆弄字节代码,至少不在Scala中。要创建类的新对象,您必须首先定义此类,并且只有在事先知道要扩展的类时才可以实现。所以不,这是不可能的(至少非常不方便)。

但是,根据您的具体用例,可以模拟这种情况,例如,使用合成加隐式转换:

implicit class SomeClassAView(x: SomeClass) extends A {
    // Implement A methods using x object
}

def expectingA(x: A) { ... }

val x: SomeClass = ...
expectingA(x)  // x will be implicitly converted to SomeClassAView which extends A

答案 1 :(得分:1)

如果T未知,则可以轻松处理动态编译:

apm@mara:~/goof$ scalam -cp /tmp
Welcome to Scala version 2.11.0-M7 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> new ts.X {}
res0: ts.X = $anon$1@13ba518f

scala> import tools.reflect.ToolBox
import tools.reflect.ToolBox

scala> import reflect.runtime._
import reflect.runtime._

scala> import universe._
import universe._

scala> val tb = currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@62920919

scala> tb.eval(tb.parse("new ts.X with ts.Y {}"))
res2: Any = __wrapper$1$88859f071ea8497cb9bf4b87aa027c85.__wrapper$1$88859f071ea8497cb9bf4b87aa027c85$$anon$1@5fa8881b

scala> res2.asInstanceOf[ts.X with ts.Y]
res3: ts.X with ts.Y = __wrapper$1$88859f071ea8497cb9bf4b87aa027c85.__wrapper$1$88859f071ea8497cb9bf4b87aa027c85$$anon$1@5fa8881b

an issue使REPL编译的类对工具箱可见。

现在,请自己动手:

scala> val rtm = runtimeMirror($intp.classLoader)
rtm: reflect.runtime.universe.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@5349c9cb of type class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)] and parent being scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@115f5925 of type class scala.reflect.internal.util.ScalaClassLoader$URLClassLoader with classpath [file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/resources.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jsse.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jce.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/charsets.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rhino.jar,file:/home/apm/scala-2.11.0-M7/lib/akka-actors.jar,file:/hom...
scala> val rtb = rtm.mkToolBox()
rtb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@58f59add

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

package foo
class Foo

// Exiting paste mode, now interpreting.


scala> rtb.eval(rtb.parse("new foo.Foo"))
res6: Any = foo.Foo@7c20db7f
相关问题