17

如果函数接受结构类型,则可以定义为:

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);
}

如果您对我的示例中由 scalac 生成的类进行反编译(到 Java),您可以看到参数doTheThings是类型Object的,并且实现使用反射来调用参数上的方法(即duck.quack

我的问题是为什么要反思?难道不能只使用匿名和调用虚拟而不是反射吗?

这是为我的示例翻译(实现)结构类型调用的方法(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();}
    });
  }
}
4

2 回答 2

15

考虑一个简单的命题:

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(它们没有方法句柄)......

于 2011-12-16T20:11:42.703 回答
10

除了您的代理对象在结构类型上实现方法之外,它还需要对 Any (equals, hashCode, toString, isInstanceOf, asInstanceOf) 和 AnyRef(getClass, wait, notify) 上的所有方法进行适当的传递实现、 notifyAll 和同步)。虽然其中一些是直截了当的,但有些几乎不可能做到正确。特别是,列出的所有方法在 AnyRef 上都是“最终的”(用于 Java 兼容性和安全性),因此您的代理对象无法正确实现。

于 2011-12-16T20:12:56.183 回答