问题
When a closure's resolveStrategy is set to DELEGATE_ONLY
or DELEGATE_FIRST
, resolution is different in nested closures between methods and properties of the delegate. For example, in the following, x
resolves to f
's delegate (what I expect), but keySet()
resolves to g
's delegate.
def g = {->
def f = {
{-> [x, keySet()]}()
}
f.resolveStrategy = Closure.DELEGATE_ONLY
f.delegate = [x: 1, f: 0]
f()
}
g.delegate = [x: 0, g: 0]
g()
Result: [1, ['x', 'g']]
Whereas without the nested closure
def g = {->
def f = {
[x, keySet()]
}
f.resolveStrategy = Closure.DELEGATE_ONLY
f.delegate = [x: 1, f: 0]
f()
}
g.delegate = [x: 0, g: 0]
g()
Result: [1, ['x', 'f']]
Is this behavior expected and documented somewhere? Is it a bug?
回答1:
I believe it is a bug. If you change the map for a Expando
it behaviors differently:
f = {
g = {
{ -> keySet() }()
}
g.delegate = new Expando(a: 1000, b: 900, c: 800, keySet: { 'g keyset' })
g.resolveStrategy = Closure.DELEGATE_ONLY
g()
}
f.delegate = new Expando(a: 90, x: 9, y: 1, keySet: { 'f keyset' })
assert f() == 'g keyset'
f = {
g = {
{ -> keySet() }()
}
g.delegate = [a: 1000, b: 900, c: 800]
g.resolveStrategy = Closure.DELEGATE_ONLY
g()
}
f.delegate = [a: 90, x: 9, y: 1]
assert f().toList() == ['a', 'b', 'c'] // fails :-(
Maybe filling a JIRA?
回答2:
I discovered a workaround if you never want to fall through to the owner (ie, DELEGATE_ONLY
): you can set both the delegate and the owner to the same value:
def g = {->
def f = {
{-> [x, keySet()]}()
}
def d = [x: 1, f: 0]
f = f.rehydrate(d, d, f.thisObject)
f()
}
g.delegate = [x: 0, g: 0]
g()
Result: [1, ["x", "f"]]
Note that f.owner = d
does not work: while there is no error, it seems to be a no-op. You must use rehydrate
.
来源:https://stackoverflow.com/questions/27627463/nested-closure-resolution-different-between-methods-and-properties