如果函数接受结构类型,则可以定义为:
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();}
});
}
}
答案 0 :(得分:14)
考虑一个简单的命题:
type T = { def quack(): Unit; def walk(): Unit }
def f(a: T, b: T) =
if (a eq b) println("They are the same duck!")
else println("Different ducks")
f(x, x) // x is a duck
它会在您的提案下打印Different ducks
。您可以进一步优化它,但是您无法使用代理保持参照等式完整。
一种可能的解决方案是使用类型类模式,但这需要传递另一个参数(即使是隐式)。不过,它更快。但这主要是因为Java反射速度的跛足。希望方法句柄可以解决速度问题。不幸的是,Scala没有计划放弃Java 5,6和7(它没有方法句柄)一段时间......
答案 1 :(得分:10)
除了你的代理对象在结构类型上实现方法之外,还需要对Any上的所有方法(equals,hashCode,toString,isInstanceOf,asInstanceOf)和AnyRef(getClass)进行适当的传递实现。 wait,notify,notifyAll和synchronized)。虽然其中一些是直截了当的,但有些人几乎不可能做对。特别是,所有列出的方法都是AnyRef上的“final”(用于Java兼容性和安全性),因此代理对象无法正确实现。