首页 > 解决方案 > 如何在 Groovy 中访问循环外的变量

问题描述

初学者警告!我有一个简单的 Groovy 脚本,旨在将参数列表分解为键值对,存储在关联数组(HashMap?)中。该代码在拆分参数之前工作正常,但是当它尝试将结果放回数组时,它会引发异常,说明它无法访问元素。我想这样做的原因是它无法访问在循环外声明的变量。

这是脚本:

def input = "https://weyland-yutani.corp/engineering/bio?param1=1&param2=2"
def params = [:]                      // wanna store key-value pairs here

if (input.split('\\?').size() >= 2) {
  def p = input.split('\\?').last()   // get the param string

  p.split('\\&').each {               // cut the string into an argument list
    def keyval = it.split('=')        // cut the argument into a key-value pair
    println keyval                    // <-- prints "[param1, 1]", looks okay
    
    params[keyval[0]].put(keyval[1])  // ERROR: "Cannot invoke method put() on null object"
    //params[keyval[0]].add(keyval[1])  // ERROR, same sh**
  }
}

错误信息:

Caught: java.lang.NullPointerException: Cannot invoke method put() on null object
java.lang.NullPointerException: Cannot invoke method put() on null object
    at jdoodle$_run_closure1.doCall(jdoodle.groovy:10)
    [...]

正如本文所述,您声明变量的方式会影响其范围,但我的尝试都没有成功。你能给我一个建议,我错过了什么吗?

标签: groovyscope

解决方案


以下代码:

def input = "https://weyland-yutani.corp/engineering/bio?param1=1&param2=2"
def params = input.tokenize('?').last().tokenize('&').collectEntries { keyval -> 
  keyval.tokenize('=')
}

println params.getClass()
println params

演示了这样做的一种方法。运行时,将打印:

─➤ groovy solution.groovy
class java.util.LinkedHashMap
[param1:1, param2:2]

─➤

作为替代方案,如果您可以使用外部库,则可以使用 url 解析类。这个来自 HttpBuilder 的例子(在这一点上有点过时了,可能还有其他的):

@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.2')
import groovyx.net.http.URIBuilder

def input = "https://weyland-yutani.corp/engineering/bio?param1=1&param2=2"
def uri = new URIBuilder(input)

println uri.query.getClass()
println uri.query

它在运行时打印:

─➤ groovy solution2.groovy
class java.util.HashMap
[param1:1, param2:2]

─➤

再举一个例子,这次使用 google http 客户端库类GenericUrl

@Grab('com.google.http-client:google-http-client:1.39.1')
import com.google.api.client.http.GenericUrl

def input = "https://weyland-yutani.corp/engineering/bio?param1=1&param2=2"
def url = new GenericUrl(input)

println (url instanceof Map)
url.each { k, v -> 
  println "$k -> $v"
}
println "value of param1: ${url.param1}"

其中,执行时打印:

─➤ groovy solution3.groovy
true
param1 -> [1]
param2 -> [2]
value of param1: [1]

─➤

应该指出的是,谷歌在这里做了正确的事情。当询问参数的值时,答案应该是一个列表。这是因为您可以说?a=1&a=2&a=3,根据我的理解,不应将其解释为替换 的值a,而应将其解释为值a的列表1, 2, 3

因此,当您向谷歌图书馆询问参数的值时,您会得到一个列表,在这种情况下恰好是一个参数长。


推荐阅读