0
class Box {
    Closure click

    Box () {
        click = {}
    }

    void onClick() {
        click()
    }
}

class TextBox extends Box {
    List<String> content

    TextBox (String[] a) {
        super()
        content = a
    }
}

class Main {
    public static void main(String[] args) {
        Main m = new Main()
    }

    Main() {
        String[] a = ["Hello world!"]
        Box b = new TextBox(a)
        b.click = {content.add("You clicked this box!")}
        b.onClick()  //throws Exception
    }
}

(显然,上面是一个简化;实际上,这些类涉及更多,并且 onClick() 的调用是由于单击 JFrame)

现在,当我尝试运行它(即运行 Main.main())时,我得到一个异常:线程“AWT-EventQueue-0”中的异常 groovy.lang.MissingPropertyException:没有这样的属性:类的内容:Main

显然,出于某种原因,它是在 Main 中搜索 List,而不是在 TextBox 或 Box 中搜索它的调用位置。我也尝试过使用它,所有者和委托,但它们也都指向 Main。我通过将其作为参数来设法使其工作:

...
void onClick() {
    click(this)
}
...
b.click = {it.content.add("You clicked this box!")}

然而,实际上需要将“this”传递给一个闭包,以便它能够知道它是从哪里调用的,这似乎很奇怪。没有更优雅的解决方案吗?此外,即使确实不可能进入 TextBox 范围,是否有可能进入 Box 范围?

4

2 回答 2

1

请参阅闭包groovy 文档。注意隐式变量:this、owner 和 delegate。
编辑:调用前修复委托:

b.click = {content.add("You clicked this box!")}
b.click.delegate = b
于 2013-05-21T22:33:33.753 回答
1
Main() {
    String[] a = ["Hello world!"]
    Box b = new TextBox(a)
    println "1:- $b.click.delegate" //Will print TextBox
    b.click = {
        println "2:- $b.click.delegate" //Will print Main

        //Since the closure is now defined inside Main(), 
        //Main becomes the delegate. Reset the delegate to TextBox.
        b.click.delegate = b

        println "3:- $b.click.delegate" //Will print TextBox
        content.add("You clicked this box!")
    }
    println "4:- $b.click.delegate" //Will print Main
    b.onClick()

    println b.content //Will print [Hello world!, You clicked this box!]
}

//Output:
1:- TextBox@c166770
4:- Main@6dbdc863
2:- Main@6dbdc863
3:- TextBox@c166770
[Hello world!, You clicked this box!]

注意事项:

  • 序列 4 出现在 2 和 3 之前,因为在那个时间点没有调用/调用闭包。
  • 序列 1 打印TextBox但序列 4 打印Main。请注意,从现在到现在delegate(在定义闭包之后b.click)已经改变了。TextBoxMain

为了让事情变得更容易,Main你可以修改onClick()

void onClick() {
    click.delegate = this
    click()
}

有关详细信息,请参阅此脚本

于 2013-05-22T04:58:31.500 回答