是否可以更改闭包的所有者?

时间:2011-04-30 21:01:30

标签: groovy

我在A类上有一个静态闭包,它将调用委托给B类。但是,当在一个A实例上向A上的静态闭包发出一个call()时,我似乎无法访问实例属性。 A.不要太惊讶,因为我正在使用静态闭包。解决此问题的一种方法是将实例化的A设置为闭包委托。但是,我需要将B类作为静态闭包的委托。

无论如何我可以更改静态闭包的所有者,所以它指向实例化的A类而不是静态?并保持B作为代表?或者这不可能吗?

4 个答案:

答案 0 :(得分:5)

你错了......你可以改变Closure的所有者,但是它是多么可取,我不知道(因为设置者是私人的,所以必须有这样的理由)。无论如何,这是一个例子:

// Define a Person, with a closure to return a property
class Person {
  String name
  int age
  Closure named = { -> "returned $name" }
}

// Define another Class with a similar property
class Furniture {
  String name
  int age
}

// Create our two objects
def tim = new Person( name:'tim', age:26 )
def chair = new Furniture( name:'chair', age:3 )

// Prints 'returned tim'
println tim.named()

// Add the closure from tim to the chair
chair.metaClass.named = tim.named
// Prints 'returned tim'
println chair.named()

// Change the owner to the chair instance
tim.named.@owner = chair
// prints 'returned chair'
println chair.named()
// prints 'returned chair'
println tim.named()

如您所见,我们可以将所有者从Person类更改为Furniture类。

然而,在实践中,您可能希望设置关闭而不是所有者的委托,但是没有您想要实现的示例,不可能说这是否是您想要的

答案 1 :(得分:0)

我发现覆盖所有者的最简单方法是重新声明闭包的实例:

    def myClosure = {  return this}

    def myOwnClass = new String('aa')
    assert myClosure.getClass().newInstance(myOwnClass,myOwnClass)() == myOwnClass
    assert myClosure.getClass().newInstance(myOwnClass,myOwnClass)() == 'aa'

答案 2 :(得分:0)

给出一个(这里简化的)真实世界的例子来说明来自@tim_yates的好答案:

/** we want to use code completion and easy refactoring/debugging IDE capabilities
 * (without "manual String code parsing") when we refer to very static project
 * properties so working with them in a structured "enum-way" is useful */
@TypeChecked  enum ProjectId {

  foo( 'fooapp' )
  bar( 'app-bar', { idAnt = 'proj.bar' } )
  //bar( 'app-bar', { ProjectId it -> it.idAnt = 'proj.bar' } )  //(1)
  // ...
  ;

  // some static props of projects (may be many!)

  String id     // e.g. some standard repo name in a central dev store
  String idAnt  // e.g. some other id used in ANT scripts

  Class<BaseEnvId> envIdClass = EnvIdCommon  // default
  // ...

  /** the enum constructor */   
  ProjectId(  String _id,  Closure<Void> customizeDefaults = null  ) {
    id    = _id
    idAnt = id
    if ( customizeDefaults ) {

      // @owner-change so we do not have to use the clumsy/verbose syntax from (1)
      // (above and below) otherwise the runtime(!) compiler would complain that 
      // ProjectId.idAnt (static field) does not exist (which is right)

      customizeDefaults.@owner = this
      customizeDefaults()
      //customizeDefaults( this )  //(1)
    }
  }
}

答案 3 :(得分:-1)

答案是:这是不可能的。一个人无法改变关闭的所有者。