1

这里还有一些其他问题相似但完全不同,我需要将其作为一个新问题提出:

我创建了一个空类,我们称之为测试。它没有任何属性或方法。然后我遍历键/值对的映射,动态创建以键命名并包含值的属性......就像这样:

def langMap = [:]
langMap.put("Zero",0)
langMap.put("One",1)
langMap.put("Two",2)
langMap.put("Three",3)
langMap.put("Four",4)
langMap.put("Five",5)
langMap.put("Six",6)
langMap.put("Seven",7)
langMap.put("Eight",8)
langMap.put("Nine",9)

langMap.each { key,val ->
    Test.metaClass."${key}" = val
}

现在我可以通过这样创建的新方法访问这些:

Test.metaClass.twoPlusThree = { return Two + Three }
println test.twoPlusThree()

不过,我想做的是从字符串动态加载一组指令,例如“二+三”,动态创建一个方法来评估结果,然后对包含表达式的许多字符串迭代重复此过程我碰巧有。

问题:a)首先,是否有更好,更优雅的方式来做到这一点(基于我提供的信息)?b)假设这条路径是可行的,从字符串动态构造这个闭包的语法是什么,其中字符串引用的变量名仅在此类的方法中有效?

谢谢!

4

1 回答 1

2

我认为正确的答案取决于您实际尝试做的事情。输入字符串可以是更复杂的表达式,比如'(Two + Six) / Four'

如果您希望允许更复杂的表达式,您可能希望直接将字符串计算为 Groovy 表达式。在 GroovyConsole 或 Groovy 脚本中,您可以直接调用evaluate,这将在该脚本的上下文中计算表达式:

def numNames = 'Zero One Two Three Four Five Six Seven Eight Nine'.split()

// Add each numer name as a property to the script.
numNames.eachWithIndex { name, i ->
    this[name] = i
}

println evaluate('(Two + Six) / Four') // -> 2

如果您不在这些脚本友好的世界之一,您可以使用GroovyShell该类:

def numNames = 'Zero One Two Three Four Five Six Seven Eight Nine'.split()
def langMap = [:]
numNames.eachWithIndex { name, i -> langMap[name] = i }

def shell = new GroovyShell(langMap as Binding)
println shell.evaluate('(Two + Six) / Four') // -> 2

但是,请注意使用 eval 是非常危险的。如果输入字符串是用户生成的,我不建议你这样做;用户可以输入类似的"rm -rf /".execute()内容,并且根据脚本的权限,从执行该脚本的任何位置删除所有内容。您可以首先验证输入字符串是否“安全”(可能检查它是否仅包含已知的运算符、空格、括号和数字名称),但我不知道这是否足够安全。

另一种选择是为这些表达式定义自己的迷你语言,然后使用ANTLR之类的东西解析它们。但是,同样,这真的取决于你想要完成什么。

于 2012-07-15T01:34:07.943 回答