使用MetaProgramming添加类似于eachWithIndex的collectWithIndex和injectWithIndex

时间:2015-11-08 04:17:33

标签: groovy

请帮助一个元编程配置,这样我就可以添加名为collectWithIndex和injectWithIndex的集合方法,它们以类似于eachWithIndex的方式工作,但当然包括collect和inject的基本功能。新方法将接受两个(带有map的三个)参数闭包,就像eachWithIndex一样。我希望能够在许多不同的脚本中使用这些方法。

用例:

List one = [1, 2, 3]
    List two = [10, 20, 30]
    assert [10, 40, 90] == one.collectWithIndex { value, index ->
    value * two [index]
    }

一旦开发了该方法,那么它将如何提供给脚本?我怀疑将使用特殊扩展信息创建一个jar文件,然后将其添加到类路径中。

非常感谢提前

1 个答案:

答案 0 :(得分:0)

我仍然确定,这不是一个正确的SO问题,但我将举例说明如何为多个脚本丰富元类。

Idea基于basecript,在其构造函数中为List的metaClass添加了所需的方法。你必须自己实现收集逻辑,通过它很容易。你可以使用包装

import org.codehaus.groovy.control.CompilerConfiguration

class WithIndexInjector extends Script {
    WithIndexInjector() {
        println("Adding collectWithIndex to List")
        List.metaClass.collectWithIndex {
            int i = 0
            def result = []
            for (o in delegate) // delegate is a ref holding initial list.
                result << it(o, i++) // it is closure given to method
            result
        }
    }

    @Override Object run() {
        return null
    }
}

def configuration = new CompilerConfiguration()
configuration.scriptBaseClass = WithIndexInjector.name
new GroovyShell(configuration).evaluate('''
    println(['a', 'b'].collectWithIndex { it, id -> "[$id]:$it" })
''')
// will print [[0]:a, [1]:b]

如果您希望以更多功能方式执行此操作,而无需重复收集逻辑,则可以使用包装代理关闭。我希望它会慢一点,但也许这不是一个交易。只需将collectWithIndex替换为以下实现。

List.metaClass.collectWithIndex {
    def wrappingProxyClosure = { Closure collectClosure, int startIndex = 0 ->
        int i = startIndex
        return {
            collectClosure(it, i++) // here we keep hold on outer collectClosure and i, and use call former with one extra argument. "it" is list element, provided by default collect method.
        }
    }
    delegate.collect(wrappingProxyClosure(it))
}

offtopic:在SO社区,你当前的问题只会吸引弊端,而不是答案。

相关问题