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

时间:2017-06-26 12:38:48

标签: dictionary groovy

我需要通过密钥的动态名称对映射/属性进行空安全访问。 Map本身可以为null。我想出了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和地图键的类型都为java.lang.String,为什么map?.(keyName)不会返回值?为什么map?.(keyName as String)会返回?    

链接

签入Groovy web console

2 个答案:

答案 0 :(得分:5)

括号只是控制评估的优先级。使用(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 - 当然对地图更安全。我个人更喜欢第三种方法。

您可能想知道为什么def map = [(keyName): 'value']可以使用keyName的值作为键,但map?.(keyName)不适用于使用keyName的值进行检索,但是原因很简单。检索的点符号仅适用于String键。使用括号定义地图适用于任何对象类型。因此,在使用括号中的键定义地图时,您可以使用任何Object作为键,但是您只能使用带有点符号的String键从地图中提取对象,因此这里的语义与括号的语义不同。

答案 1 :(得分:3)

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'