【问题标题】:Groovy DSL: creating dynamic closures from StringsGroovy DSL:从字符串创建动态闭包
【发布时间】:2012-07-14 08:38:56
【问题描述】:

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

我创建了一个空类,我们称之为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()

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

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

谢谢!

【问题讨论】:

    标签: groovy closures dsl


    【解决方案1】:

    我认为正确的答案取决于您实际尝试做的事情。输入字符串可以是更复杂的表达式吗,比如'(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 之类的东西解析它们。但是,同样,这实际上取决于您要完成的任务。

    【讨论】:

    • 效果很好!我肯定需要使用 GroovyShell 版本,因为我会想要加载“语言”,然后调用未知数量的表达式。感谢有关用户在表达式中创建的值的提醒......我需要确保首先检查表达式以确保它在执行之前仅使用批准的运算符和变量名称。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2017-06-08
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多