首页 文章

如何为闭包类指定一个闭包属性

提问于
浏览
0

我有一个这样的课

class SomeClass () {
    Closure instClos

    SomeClass (Closure clos) { instClos = clos}  //constructor

    def call() {instClos()}
}

我想要做的是做这样的隐式类构造函数

SomeClass myInst = {println "hello there}
 myInst()

但这不起作用并抛出强制转换异常 . 你可以通过在封闭处写[]来调用构造函数来完成这项工作 . 但它不漂亮

SomeClass myInst = [{println "hello there}]  // or myInst = new ({println "hello there}
myInst()

是否有一种通过赋值创建对象的好方法,并将该闭包自动存储在创建的类实例上?

我觉得我在这里缺少一些groovy语法,可以对此进行排序(如果我可以避免,我不想扩展Closure)

根据目前提供的输入,我提供了一个扩展脚本来显示各种选项 . 我尝试向Closure添加一个asType闭包并尝试将作为SomeClass调用 - 但是如果我尝试从未调用asType,那么当你尝试强制时,groovy必须使用另一种机制

class SomeClass {
    Closure instClos

    SomeClass (Closure clos) {
        println "\tSomeClass constructor: Will constructor called"
        instClos = clos
    }

    def call() {
        println "\tSomeClass.call: calling closure "
        return (instClos() + "!")
    }

    SomeClass asType (Closure clos) {
        new SomeClass (instClos: clos)
    }
}

//this will call the map constructor - needs to be explicitly provided
SomeClass me = [{println "map style construction"; "echo"}]
assert me() == "echo!"

//use new to get class instance with constructor
me = new SomeClass ({println "new SomeClass () construction"; "echo"})
assert me() == "echo!"

//using layered closure approach - doesnt read well though
def someClos = {new SomeClass(it)}
def c = someClos {println "trying layered closure ";"echo"}
assert c() == "echo!"

//extending the Closure class to add a method
ExpandoMetaClass.enableGlobally()
Closure.metaClass.some =  {
    if (it ==  SomeClass) {
        new SomeClass (delegate)
    }
}

//this will call .some() on closure
me = {println "hello will using .some() "; "echo"}.some ( SomeClass)
assert me() == "echo!"

2 回答

  • 1

    无论如何我都不知道自动强制关闭 . 即使groovy有closure coercion,它的工作方式是更改闭包's type, but it'仍然是一个闭包,并且不是分层的 . 一些想法:

    1.构造函数

    class SomeClass {
        Closure instClos
        SomeClass (Closure clos) { instClos = clos}  //constructor
        def call() {instClos() + "!"}
    }
    
    def c = new SomeClass( { "echo" } )
    
    assert c() == "echo!"
    

    2. Map 构造函数

    class SomeClass {
        Closure instClos
        def call() {instClos() + "!"}
    }
    
    SomeClass c = [instClos: { "echo" }]
    
    assert c() == "echo!"
    

    3.关闭元编程

    (需要enableGlobally()

    ExpandoMetaClass.enableGlobally()
    
    Closure.metaClass.some = { new SomeClass(delegate) }
    
    def c = { "echo" }.some()
    
    assert c() == "echo!"
    

    4.另一个封闭分层

    class SomeClass {
        Closure instClos
        SomeClass (Closure clos) { instClos = clos}  //constructor
        def call() {instClos() + "!"}
    }
    
    def some = { new SomeClass(it) }
    def c = some { "echo" }
    assert c() == "echo!"
    

    5.覆盖Closure的asType

    ExpandoMetaClass.enableGlobally()
    
    def asType = Closure.metaClass.asType
    Closure.metaClass.asType = { Class c -> 
        (c == SomeClass) ? new SomeClass(delegate) : asType(c)
    }
    
    def c = { "echo" } as SomeClass
    
    assert c() == "echo!"
    
  • 0

    如果您的设计具有足够的灵活性,那么您只需要一个方法,然后您可以将其指定为接口:

    interface SomeClass {
        def call()
    }
    

    Groovy很久以前就预料到了Java 8使用 @FunctionalInterface 注释形式化的情况 . 如果将Groovy Closure分配给接口类型的变量或形式参数,其中接口只有一个方法(如上面定义的 SomeClass ),则Groovy编译器会将闭包强制转换为该接口的实例 . 因此,给定上面的接口声明,以下代码:

    SomeClass myInst = { println "hello there" }
    myInst()
    

    打印“你好” .

相关问题