【问题标题】:How does Groovy work in a dynamic way?Groovy 如何以动态方式工作?
【发布时间】:2012-11-24 05:31:11
【问题描述】:

我为静态类型语言构建了一个小型编译器。在了解了静态语言的工作原理后,我很难进入像 groovy 这样的动态语言。

在构建编译器时,我知道一旦生成机器级代码,就无法更改它! (即它的run-time)。

但是,Groovy 是如何做到这些神奇的事情的,比如在如下语句中推断类型:

def a = "string"
a.size()

就我而言,groovy 必须在运行a.size() 行之前找到a 的类型为string。似乎它是在编译时这样做的(在构建 AST 时)!但是这种语言被称为动态的。

我很困惑,请帮我弄清楚。

谢谢。

【问题讨论】:

标签: dynamic compiler-construction groovy static


【解决方案1】:

Groovy 不是简单地“调用”一个方法,而是通过元对象协议调度它。方法调用作为消息发送到对象,对象可以响应也可以不响应。使用动态类型时,对象类型无关紧要,只要它响应该消息即可。这称为duck typing

您可以在反编译 Groovy 代码时看到它(虽然不容易)。您可以使用groovyc 编译并使用其他工具进行反编译。我推荐jd-gui。由于 Groovy 的方法缓存,您不会看到该方法被显式调用(这样做是为了实现 Groovy 的简洁性能)。

对于一个简单的脚本,例如:

def a = "abcdefg"
println a.substring(2)

这将是生成的代码:

CallSite[] arrayOfCallSite = $getCallSiteArray(); Object a = "abcdefg";
return arrayOfCallSite[1].callCurrent(
    this, arrayOfCallSite[2].call(a, Integer.valueOf(2))); return null;

并且方法调用被“分派”到对象,而不是直接调用。这是一个类似于 Smalltalks 和 Ruby 方法分派的概念。正是由于这种机制,您可以拦截 Groovy 对象上的方法和属性访问。

从 Groovy 2 开始,Groovy 代码可以静态编译,因此就像您的编译器一样。

【讨论】:

  • 请注意,使用 Jad 您可以“发现”调用哪个方法,因为它提供了缓存的方法 arrayOfCallSite[2]="substring" 例如。我个人从 JAD 获取缓存方法,然后使用 JD-GUI 显示反编译的 java,因为它更清晰(JAD 制作一个包含所有闭包的文件)。
猜你喜欢
  • 1970-01-01
  • 2021-06-02
  • 1970-01-01
  • 2017-07-01
  • 2013-01-25
  • 2021-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多