【问题标题】:Groovy metaclass in GrailsGrails 中的 Groovy 元类
【发布时间】:2015-09-03 21:45:20
【问题描述】:

我在 Grails 中为 列表映射(key 是一个 Integer 但 values 是 List 的映射)添加了一个行为。如果key 不存在,我将插入Integer key 和一个value。但如果key 存在,我想将values 连接为List / 而不是替换现有的value。

/**
* E.g.
*  [1: [123, 456, 789], [2: [987, 654, 321]]]
*/
LinkedHashMap.metaClass.multiPut << { key, value ->
    delegate[key] = delegate[key] ?: [];
    delegate[key] += value
}

我的问题是: 我应该把它放在 Grails 的什么地方? 放在 Bootstrap.groovy's init 或 AST Transformation 中(如果是,怎么做?)?

【问题讨论】:

    标签: grails groovy


    【解决方案1】:

    我个人会选择 Groovy 扩展模块。这些是在 Grails 初始化阶段加载的,因此几乎可以在应用程序生命周期内的任何时间使用。

    更多关于这些扩展的信息可以在这里找到:http://mrhaki.blogspot.cz/2013/01/groovy-goodness-adding-extra-methods.html

    模块加载支持已根据此 Jira 票证添加到 Grails:https://github.com/grails/grails-core/issues/1307

    另一方面,我也没有发现使用引导程序有什么问题。

    【讨论】:

      【解决方案2】:

      看着你的“新”方法,我无法停止思考已经存在的方法:

      def map = [:].withDefault{ [] }
      assert map[ 'key' ] == []
      map[ 'key' ] << 'value'
      assert map[ 'key' ] == [ 'value' ]
      

      问题是,连接与Map 无关,该合约只关心添加或替换值。

      这里可能的问题是null-value。如果您执行map.someKey += 'aaa',如果密钥不存在,您将获得 NPE。为了确保值永远不会变成null,至少在第一次调用时是这样。这就是withDefault() 派上用场的地方。

      在上面的示例中,我使用默认值 [] 初始化了映射,这意味着如果密钥不存在,则插入新密钥并使用 [] 的值。

      您可以将[] 替换为'' 或任何其他允许连接的类型:

      def map = [:].withDefault{ "" }
      map.newKey += 'aaa'
      
      def map = [:].withDefault{ 0 }
      map.newKey += 10
      

      【讨论】:

      • 但您示例中的 map 变量的类型为 groovy.lang.MapWithDefault 而不是 LinkedHashMap 与原始问题中的一样。我仍然认为multiPut 的新方法是不安全的——+= 对于数组、数字和字符串的行为可能会有所不同,乍一看可能并不明显。
      • 我只是想指出,没有必要引入新方法,如果它们已经存在
      • @injecteer 我已经编辑了我的问题,以防我没有说清楚。你现在能帮忙吗?如果键存在,groovy 中是否存在允许我将值连接到映射的行为?
      猜你喜欢
      • 2013-04-02
      • 2012-07-29
      • 2011-02-03
      • 2011-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-07
      相关资源
      最近更新 更多