如果函数接受结构类型,可以定义为:
def doTheThings(duck: { def walk; def quack }) { duck.quack }
或者type DuckType = { def walk; def quack }
def doTheThings(duck: DuckType) { duck.quack }
然后,您可以按以下方式使用该函数:
class Dog {
def walk { println("Dog walk") }
def quack { println("Dog quacks") }
}
def main(args: Array[String]) {
doTheThings(new Dog);
}
如果您反编译(到Java)由scalac为我的示例生成的类,您可以看到doTheThings
的参数是Object
类型,实现使用反射调用参数上的方法(即 duck.quack
)。 我的问题是为什么要使用反射?难道不能只使用匿名和invokevirtual来代替反射吗?这是实现结构类型调用的一种方式(针对我的示例)(Java语法,但重点是字节码)。class DuckyDogTest {
interface DuckType {
void walk();
void quack();
}
static void doTheThing(DuckType d) {
d.quack();
}
static class Dog {
public void walk() { System.out.println("Dog walk"); }
public void quack() { System.out.println("Dog quack"); }
}
public static void main(String[] args) {
final Dog d = new Dog();
doTheThing(new DuckType() {
public final void walk() { d.walk(); }
public final void quack() { d.quack();}
});
}
}
invokevirtual
在 JVM 1.5 和 1.6 上不存在,因此 Scala 不能依赖它。Scala 2.10 实际上会弃用 JVM 1.5,但在 Scala 能够利用仅存在于 JVM 1.7 上的功能之前还需要一些时间。 - Daniel C. Sobralinvokedynamic
而不是invokevirtual
。 - Op De Cirkelinvokedynamic
将是一个替代方案,不会像问题提出的解决方案那样遭受身份丢失的问题,但这取决于不支持Java 1.5/1.6。这已经不再是天方夜谭了--社区就是否要求Scala 2.11需要Java 7进行了投票。我不知道结果如何,但这是现在正在考虑的事情。 - Daniel C. Sobral