如果我有一些对象x
,并且我想创建一个与x
具有相同类别的新实例,我可以说:
x.getClass.newInstance
如果x
属于某个(未知)类T
,则新实例也属于T
类。
但实际上我想创建一个T with A
的新实例。换句话说,我想做类似的事情:
(x.getClass with A).newInstance
但这不起作用。有可能这样做吗?
答案 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