我想要实现的是正确实施
def dynamix[A, B](a: A): A with B
Run Code Online (Sandbox Code Playgroud)
我可能知道B是什么,但不知道A是什么(但如果B有自我类型,那么我可以在A上添加一些约束).scala编译器对上面的签名很满意,但我还不知道实现的样子 - 如果可能的话.
我想到了一些选择:
你有其他可能有用的想法吗?你会推荐哪种方式?期待什么样的"挑战"?
或者我应该忘记它,因为目前的Scala限制是不可能的?
我的问题背后的意图:说我有一个业务工作流程,但它不是太严格.一些步骤具有固定顺序,但其他步骤没有,但最后必须完成所有步骤(或者其中一些步骤需要进一步处理).
更具体的例子:我有一个A,我可以添加B和C. 我不在乎先做哪个,但最后我需要A带B和C.
评论:我对Groovy不太了解,但是我想出了这个问题,我想这或多或少与我想要的一样,至少在构思上.
ste*_*ins 26
我认为这在运行时不可能严格执行,因为traits在编译时混合到新的Java类中.如果您匿名地将特征与现有类混合,您可以看到,查看类文件并使用javap,scalac创建了一个匿名的,名称受损的类:
class Foo {
def bar = 5
}
trait Spam {
def eggs = 10
}
object Main {
def main(args: Array[String]) = {
println((new Foo with Spam).eggs)
}
}
Run Code Online (Sandbox Code Playgroud)
scalac Mixin.scala; ls *.class 回报
Foo.class Main$.class Spam$class.class
Main$$anon$1.class Main.class Spam.class
虽然javap Main\$\$anon\$1回归
Compiled from "mixin.scala"
public final class Main$$anon$1 extends Foo implements Spam{
public int eggs();
public Main$$anon$1();
}
Run Code Online (Sandbox Code Playgroud)
如您所见,scalac创建了一个在运行时加载的新匿名类; 可能eggs这个匿名类中的方法创建了一个实例Spam$class并调用eggs它,但我不完全确定.
但是,我们可以在这里做一个非常hacky的技巧:
import scala.tools.nsc._;
import scala.reflect.Manifest
object DynamicClassLoader {
private var id = 0
def uniqueId = synchronized { id += 1; "Klass" + id.toString }
}
class DynamicClassLoader extends
java.lang.ClassLoader(getClass.getClassLoader) {
def buildClass[T, V](implicit t: Manifest[T], v: Manifest[V]) = {
// Create a unique ID
val id = DynamicClassLoader.uniqueId
// what's the Scala code we need to generate this class?
val classDef = "class %s extends %s with %s".
format(id, t.toString, v.toString)
println(classDef)
// fire up a new Scala interpreter/compiler
val settings = new Settings(null)
val interpreter = new Interpreter(settings)
// define this class
interpreter.compileAndSaveRun("<anon>", classDef)
// get the bytecode for this new class
val bytes = interpreter.classLoader.getBytesForClass(id)
// define the bytecode using this classloader; cast it to what we expect
defineClass(id, bytes, 0, bytes.length).asInstanceOf[Class[T with V]]
}
}
val loader = new DynamicClassLoader
val instance = loader.buildClass[Foo, Spam].newInstance
instance.bar
// Int = 5
instance.eggs
// Int = 10
Run Code Online (Sandbox Code Playgroud)
由于您需要使用Scala编译器AFAIK,这可能接近您可以做到的最干净的解决方案.这很慢,但记忆可能会有很大帮助.
这种方法非常荒谬,骇人听闻,并且违背了语言.我想各种各样的怪异虫子都可以悄悄进入; 使用Java比我更久的人警告说,乱搞乱码器会带来疯狂.
| 归档时间: |
|
| 查看次数: |
7167 次 |
| 最近记录: |