我有类似这样的课程
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!"
答案 0 :(得分:1)
我还没有意识到自动强制关闭。虽然groovy有closure coercion,但它的工作方式是更改闭包的类型,但它仍然是一个闭包,并没有分层。一些想法:
class SomeClass {
Closure instClos
SomeClass (Closure clos) { instClos = clos} //constructor
def call() {instClos() + "!"}
}
def c = new SomeClass( { "echo" } )
assert c() == "echo!"
class SomeClass {
Closure instClos
def call() {instClos() + "!"}
}
SomeClass c = [instClos: { "echo" }]
assert c() == "echo!"
(需要enableGlobally()
)
ExpandoMetaClass.enableGlobally()
Closure.metaClass.some = { new SomeClass(delegate) }
def c = { "echo" }.some()
assert c() == "echo!"
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!"
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()
打印"你好那里"。