// this method has a map args to capture all named args
// and non-named (ordered) args String s, int n, and int x
// x has a default value so is optional
// the map (here untyped) to capture the nameed args MUST COME FIRST
def m(Map args=[:], String s, int n, int x=1)
{
println "s:$s n:$n x:$x, args:$args"
}
//1: pass in named args first, then ordered
m(a: "aa", b: 3, "ss", 44, 5) // s:ss n:44 x:5, args:[a:aa, b:3]
//2: ordered args first - named args last (same result)
m("ss", 44, 5, a: "aa", b: 3) // s:ss n:44 x:5, args:[a:aa, b:3]
//3: bring the first ordered arg (s) to the start (same result)
m("ss", a: "aa", b: 3, 44, 5) // s:ss n:44 x:5, args:[a:aa, b:3]
//4: stick the ordered arg n in the middle of the named args (same result!)
m("ss", a: "aa", 44, b: 3, 5) // s:ss n:44 x:5, args:[a:aa, b:3]
//5: mix the ordered args in with the named and SKIP the arg x with default value (x=1)
m(a: "aa", "ss", b: 3, 44) // s:ss n:44 x:1, args:[a:aa, b:3]
//6: ordered arg n first - so in the wrong order (Fail!)
//m(44, "ss", a: "aa", b: 3, 5) //MissingMethodException: No signature .. of .. m() .. applicable for
// argument types: (java.util.LinkedHashMap, java.lang.Integer, java.lang.String, java.lang.Integer)
// values: [[a:aa, b:3], 44, ss, 5]
//7: no named args: Fails! (change signature to add default: Map args=[:] and it will succeed with: s:ss n:44 x:1, args:[:]
m("ss", 44) // ...No signature ... applicaple ... types (java.lang.String, java.lang.Integer)
//8: no named args: Fails! (even with default map in signature this fails!)
m("ss", 44, 5) // ...No signature ... applicaple ... types (java.lang.String, java.lang.Integer, java.lang.Integer)
test(a:"a", b: "b") // Actual myfunc([a: "a", b: "b"])
test("a", b: "b") // Actual myfunc([b: "b"], "a")
test(a: "a", "b") // Actual myfunc([a: "a"], "b")
这很糟糕,因为它实际上改变了位置参数的顺序。 1.正常的默认参数不能乱序调用 代码
def test(String a, String b, int x=1, int y=2){
a = args.get('a', a)
b = args.get('b', b)
x = args.get('x', x)
y = args.get('y', y)
println "a:$a b:$b x:$x, y:$y"
}
test("a", 'b') // Positional arguments without giving the default values
// "a:a b:b x:1 y:2"
test("a", "b", 3) // Positional arguments with giving 1 default and not the last
// "a:a b:b x:3 y:2"
test("a", "b", y:4) // Positional with Keyword arguments. Actual call test([y:4], "a", "b")
// This fails!? No signature of method, because Map is the first argument
def test1(Map args=[:], String a, String b, int x=1, int y=2){
a = args.get('a', a)
b = args.get('b', b)
x = args.get('x', x)
y = args.get('y', y)
println "test1(a:$a b:$b x:$x, y:$y, args:$args)"
}
test1("ss", "44", 5, c: "c", d: 3) // Actual test2([c: "c", d: 3], "ss", "44", 5) Matches our definition
// test1(a:ss b:44 x:5, y:2, args:[c:c, d:3, a:ss, b:44, x:5, y:2])
test1(a: "aa", b: 3, "ss", "44", 5) // Actual test2([a: "aa", b: 3], "ss", "44", 5) Nothing wrong with repeat parameters because they are in the map
// test1(a:aa b:3 x:5, y:2, args:[a:aa, b:3, x:5, y:2])
test1(a: "aa", b: 3, "ss", "44", y:5) // Actual test2([a: "aa", b: 3, y:5], "ss", "44") y is in the map, so y still has the default positional value
// test1(a:aa b:3 x:1, y:5, args:[a:aa, b:3, y:5, x:1])
test1("ss", "44", y:3) // Actual test2([y:3], "ss", "44")
// test1(a:ss b:44 x:1, y:3, args:[y:3, a:ss, b:44, x:1])
test1('a', 'b') // Pure positional arguments only required arguments given (no defaults given)
// test1(a:a b:b x:1, y:2, args:[a:a, b:b, x:1, y:2])
test1("ss", "44", 5) // Pure positional arguments one missing
// This fails!? No signature of method. Why?
test1("ss", "44", 5, 6) // Pure positional arguments all arguments given
// This fails!? No signature of method. Why?
有一个map m [B:2],并且obj[0]= a map [a:1],因此您无法确定map m是位置Map还是命名参数。 顺便说一句,我不一定推荐这些,我会尽可能使用精确的参数(我甚至更喜欢显式类型)。在我自己的代码中,有相当多的时候我会感到有点困惑,并通过添加一些显式类型来解决问题,但在某些情况下,这可能是非常有用的。
6条答案
按热度按时间ugmeyewa1#
方法调用应为
test(a: '1', b: '2')
,而不是test([a: '1', b: '2'])
。请检查文档中方法的命名参数部分。
qhhrdooz2#
也许我漏掉了一些东西,但是我认为Groovy现在还没有命名参数,有discussions和proposals,但是我不知道任何官方的东西。
对于您的情况,我认为Map扩展 * 可能 * 会有帮助,但不是在所有情况下。在获取值时,它遵循Map值声明的顺序:
对于类,我可以建议使用Groovy's作为运算符吗?
bbuxkriu3#
命名参数支持非常灵活,但是文档有点单薄。下面是我发现的一些规则。注意,我试图在术语"parameters"(在方法中声明)和"args"(传递给方法调用)的使用中做到明确无误。
(a: "aa")
就足够了,您不需要([a: "aa"])
x
)args=[:]
,使命名的args成为可选参数,但如果您有其他可选参数(请参阅下面的最后一个示例),则此操作效果不佳。以下是一些例子:参数不需要输入,但为了清楚起见,我添加了类型。
rjjhvcjd4#
感谢Will P的评论,我已经找到了适合我的问题的解决方案:
如果定义一个没有类型的参数,就可以传入所有类型,包括hashMap。
这样,我可以使用单个命名参数,但也可以使用Map!
gcmastyq5#
我非常讨厌groovy处理位置参数和命名/默认参数的方式,太糟糕了,Python毫无疑问地做得很好。
问题
1.用参数名调用函数实际上创建了一个Map,并使该Map成为第一个参数。
代码
这很糟糕,因为它实际上改变了位置参数的顺序。
1.正常的默认参数不能乱序调用
代码
当然,你可以重写函数使参数匹配你想要的位置,当你有很多参数时,这是一个巨大的麻烦。
1.使用Map作为第一个参数不允许使用纯位置参数
代码
我的解决方案...
最终,我的解决方案是接受任意数量的参数作为Object,并将这些参数Map到已定义的参数Map。
代码
我对这个解决方案不是很满意,但它使关键字参数满足了我的需要。
ep6jt1vc6#
这个问题引起了我的思考,我想出了一个灵活、有趣(如果不可怕的话)的解决方案。
这个签名似乎可以接受任何参数的组合:
它对它们做的事情大多是可以预测的。
唯一令人恼火的奇怪之处是,您将map作为第一个位置参数传递。
然而
有一个map m [B:2],并且obj[0]= a map [a:1],因此您无法确定map m是位置Map还是命名参数。
顺便说一句,我不一定推荐这些,我会尽可能使用精确的参数(我甚至更喜欢显式类型)。在我自己的代码中,有相当多的时候我会感到有点困惑,并通过添加一些显式类型来解决问题,但在某些情况下,这可能是非常有用的。