如何在 Groovy 方法中使用可选的命名参数

Sun*_*nov 6 groovy named-parameters

使用已记录的命名和位置参数(或具有默认值的 args)的混合,如何在不指定任何命名参数的情况下调用方法?

我试图在不破坏其他人的代码的情况下扩展现有的共享方法,这种方法看起来很有希望,但下面的例子失败了:

?def test(Map args, some, thing='default value'){
    "$some $thing";
}

//good - adding any named parameter works
//test('yet', 'another good', anything:'notneeded');

//but not specifying named parameter fails
test('this', 'fails');???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

我无法找到有关此行为的文档,而且看起来很奇怪。

bla*_*ild 9

groovy 解析器需要一些信息来确定要执行的方法。

所以如果你写:

test('yet', 'another good', anything:'notneeded')
Run Code Online (Sandbox Code Playgroud)

这被翻译成:

test([anything:'notneeded'], 'yet', 'another good')
Run Code Online (Sandbox Code Playgroud)

即所有命名参数样式的参数(带有冒号)都被放入一个映射中并放置在参数列表的开头。所有剩余的参数都放置在此之后。

所以 Groovy 现在会查找签名test(Map, String, String)并正确找到您的方法。

如果没有命名参数,则不会发生这种转换,并且签名将为test(String, String),它没有匹配的方法。

所以解决方案是创建一个额外的方法来匹配没有命名参数的调用:

?def test(some, thing='default value'){
    test([:], some, thing)
}
Run Code Online (Sandbox Code Playgroud)

这样,既支持命名调用又支持未命名调用。


emi*_*les 0

这取决于现有方法签名的样子。假设您有一个带有 1 个参数的现有方法,如下所示:

def test(String input) { ... }
Run Code Online (Sandbox Code Playgroud)

如果您想添加传递一个附加位置参数的功能,您只需添加一个重载即可:

def test(String input, String output) { ... }
Run Code Online (Sandbox Code Playgroud)

如果您想添加可选的命名参数,您可以添加此重载:

def test(Map namedArgs, String input) { ... }
Run Code Online (Sandbox Code Playgroud)

如果您调用“test('')”,它将运行原始方法。“test('one', 'two')”将运行 secobd 版本。“test('one',two: 'two')”将运行第三个。

如果您想支持 2 个位置参数和一个或多个命名参数,您可能需要添加第四个重载。