3

我正在使用 Groovy 编写一个处理 BASIC 的 DSL,我想要一些关于如何处理多(多于 2 个)维数组的帮助。

我正在处理这样的基本代码:

100 LET X = A(1, 2, 3)

处理 1 维情况很容易 - 只需创建一个返回 A 元素的闭包(通过 MOP),而对于 2 维,我可以在表单中执行相同操作

A(2, 3) == A.get(2)[3]

但是如何处理无限维度的数组呢?

更新:为了更清楚一点,问题是如何在 DSL 上下文中动态返回数组值?脚本解释器将 A(1, 2, 3) 视为我可以使用 MOP 拦截的函数调用。但是如何在该上下文中返回数组元素的值?

4

2 回答 2

2

如果您使用嵌套列表建模的 n 维数组(不是最节省内存的方法,但很容易实现),并且想要访问索引处的元素,[i_1, i_2, ... , i_n]您可以这样做:

def getElementAt(arr, ... indexes) {
    indexes.inject(arr) { a, ind -> a[ind] }
}

// A 2x2x3 array implemented with nested lists.
def arr = [[[1,1,1], [1,1,5]], [[1,1,1], [1,1,1]]]

// I want to get that 5!
assert getElementAt(arr, 0, 1, 2) == 5

// The line above is equivalent to:
assert arr[0][1][2] == 5

允许您迭代集合并从inject初始值开始累积给定操作的结果。在这种情况下,我们迭代我们想要从数组中获取的索引,并以整个数组开始迭代;然后每次迭代返回给定索引处的子数组,该索引将在下一次迭代中使用。如果您碰巧使用的索引少于预期,它将返回一个列表而不是整数,例如getElementAt(arr, 0, 1) == [1, 1, 5].

于 2012-06-15T21:35:11.880 回答
1

最后,我决定解析输入并使用它通过 MOP 构建闭包:

    /* array references look like functions to Groovy so trap them */
    BinsicInterpreter.metaClass."$varName" = {Object[] arg ->
        def answer = "package binsic; $varName"
        arg.each { 
            answer = answer + "[$it]"
        }
        def something = shell.evaluate(answer)
        return something
    }

所以如果我们有:

100 LET X = A(10, 20, 3)

MOP 将 A(...) 捕获为函数调用,上面的代码给了我 A[10][20][3]

于 2012-06-17T21:51:55.197 回答