То, чего я хотел бы достигнуть, имеет надлежащую реализацию для
def dynamix[A, B](a: A): A with B
Я могу знать, каков B, но не знайте то, что A (но если B имеет сам тип затем, я мог бы добавить некоторые ограничения на A). scala компилятор доволен вышеупомянутой подписью, но я еще не мог выяснить, как реализация будет похожа - если это будет возможно вообще.
Некоторые опции, которые прибыли по моему мнению:
У Вас есть какие-либо другие идеи, которые могли бы работать? Какой путь Вы рекомендовали бы? Какие "проблемы" ожидать?
Или я должен забыть это, потому что это не возможно с текущими ограничениями Scala?
Намерение позади моей проблемы: Скажите, что у меня есть бизнес-рабочий процесс, но это не слишком строго. Некоторые шаги зафиксировали порядок, но другие не делают, но в конце все они должен быть сделан (или некоторые из них требуемый для последующей обработки).
Немного более конкретный пример: у Меня есть A, я могу добавить B и C к нему. Я не забочусь, который сделан сначала, но в конце мне будет нужно с B с C.
Комментарий: Я не знаю слишком много о Groovy, но ТАК открылся этот вопрос, и я предполагаю, что это - более или менее то же как, что я хотел бы, по крайней мере, концептуальный.
Я считаю, что это невозможно сделать строго во время выполнения, потому что черты смешиваются при компиляции. время в новые классы 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)
}
}
scalac Mixin.scala; ls * .class
возвращает
Foo.class Main $ .class Spam $ class.class
Main $$ anon $ 1.класс Main.class Спам.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();
}
Как видите, scalac создает новый анонимный класс, который загружается во время выполнения; предположительно метод яйца
в этом анонимном классе создает экземпляр Spam $ class
и вызывает для него яйца
, но я не совсем уверен.
Однако , здесь мы можем сделать довольно хитрый трюк:
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
Поскольку вам требуется для использования компилятора Scala, AFAIK, это, вероятно, близко к самому чистому решению, которое вы могли бы сделать, чтобы получить это. Это довольно медленно, но мемоизация, вероятно, очень поможет.
Этот подход довольно нелепый, хакерский и идет вразрез с сутью языка. Я полагаю, что сюда могут закрасться всякие чудаковатые ошибки; Люди, которые использовали Java дольше меня, предупреждают о безумии, связанном с возиться с загрузчиками классов.