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

时间:2016-11-26 15:28:26

标签: groovy constructor variable-assignment

我有类似这样的课程

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 个答案:

答案 0 :(得分:1)

我还没有意识到自动强制关闭。虽然groovy有closure coercion,但它的工作方式是更改闭包的类型,但它仍然是一个闭包,并没有分层。一些想法:

1。构造

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

def c = new SomeClass( { "echo" } )

assert c() == "echo!"

2。地图构造函数

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。覆盖关闭' 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!"

答案 1 :(得分:0)

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

interface SomeClass {
    def call()
}

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

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

打印"你好那里"。