为什么通过括号中的变量访问groovy map总是返回null?

jfewjypa  于 2022-11-01  发布在  其他
关注(0)|答案(3)|浏览(188)

简短
我需要通过键的动态名称对map/property进行空值安全访问。Map本身可以为空值。我已经想到了map?.(keyName),但不知道为什么它不能像预期的那样工作,总是返回null

代码示例

def map = [key: 'value']
def keyName = 'key'

map.each({ key, value -> println("[${key.class}]: [${value.class}]")})
println("keyName class is [${keyName.class}]")

println(map?.(keyName))                        // null  <--------- My question

// Alternatives that work well
println(map?.(keyName as String))              // value
println(map?.(keyName as java.lang.String))    // value
println(map?.get(keyName))                     // value

​
  • 输出 *
[class java.lang.String]: [class java.lang.String]
keyName class is [class java.lang.String]
null
value
value
value

问题

如果keyName和Map键都是java.lang.String类型,为什么map?.(keyName)不返回值?为什么map?.(keyName as String)返回值?

个链接

已签入Groovy web console

j2qf4p5b

j2qf4p5b1#

圆括号只是控制计算的优先级。对于(keyName),圆括号中没有要计算的内容,因此圆括号没有意义,map?.(keyName)map?.keyName相同,即map?.get('keyName')
对于map?.(keyName as String),括号中有一些要计算的内容,因此它首先进行计算,并解析为map?.'key',即map?.get('key')
如果你想使用一个动态键值,你必须确保它是由某个表达式来计算的。各种选择(有些你已经找到了)包括:

  • map?.(keyName as String)
  • map?.get(keyName)
  • map?."$keyName"
  • map[keyName]

虽然最后一个选择不是null-当然关于Map更安全。我个人更喜欢第三种方法。
您可能想知道为什么def map = [(keyName): 'value']可以使用keyName的值作为键,而map?.(keyName)不能使用keyName的值进行检索,但是原因很简单。2点标记法只适用于字符串键。3用括号定义的Map适用于任何对象类型。所以当你用括号中的键定义一个Map时,你可以使用任何Object作为键,但是你只能从一个带有点标记的String键的Map中提取对象,因此这里关于括号的语义是不同的。

z8dt9xmd

z8dt9xmd2#

Groovy将map?.(keyName)解析为map?.get('keyName')。使用map?.keyName会产生相同的结果:

def map = [key: 'value', keyName: 'gotcha']
def keyName = 'key'

result = map?.(keyName)

assert result == 'gotcha'
assert map?.keyName == 'gotcha'
qyuhtwio

qyuhtwio3#

正如@吸血鬼所指出的
用于检索的点标记法仅适用于String键
但是在我的例子中,我需要动态地设置key,而它不是字符串key。所以我最终的解决方案是遍历map,直到我找到我的key部分:

def SetMapEntry(String key, String value, Map map) {
  def entry = map
  def keyRoute = key.split('\\.')
  def entryLength = keyRoute.size()

  key.split('\\.').eachWithIndex{it,index->
    if (entryLength - 1 == index) {
      entry.(it as String) = value
    }
    else {
      entry = entry?.get(it)
    }
  }
}

相关问题