这里还有一些其他问题类似,但差异很大,我需要将其作为一个新问题提出来:
我创建了一个空类,我们称之为Test。它没有任何属性或方法。然后我遍历一个键/值对的映射,动态创建为键命名的属性并包含值......如下所示:
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()
我想做的是从String中动态加载一组指令,比如“Two + Three”,动态创建一个方法来评估结果,然后迭代地重复这个过程包含我碰巧拥有的表达式。
问题: a)首先,是否有一种更好,更优雅的方式(基于我给出的信息)? b)假设这个路径是可行的,从字符串动态构造这个闭包的语法是什么,其中字符串引用的变量名仅在该类的方法中有效?
谢谢!
答案 0 :(得分: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
但是,请注意using eval is very risky。如果输入字符串是用户生成的,我不建议你这样做;用户可以输入类似"rm -rf /".execute()
的内容,并根据脚本的特权擦除脚本执行的所有内容。您可以首先验证输入字符串是否“安全”(可能只检查它包含已知的运算符,空格,括号和数字名称),但我不知道这是否足够安全。
另一种选择是为这些表达式定义自己的迷你语言,然后使用ANTLR之类的东西对其进行解析。但是,这又取决于你想要实现的目标。