2012-12-22 80 views
33

我有方法命名參數

def test(String a, String b) { } 

,我想有一個動態的參數映射到調用它。 我總是儘管這

test(['1','2']); //valid call 

test([a:'1',b:'2']); //=> does not work 

會工作。但事實並非如此。所以我記得the spread operator,但不能得到它的工作....

有沒有一種方法來調用像上面那種方法與某種地圖作爲參數,而不是單個參數?

+1

我不知道常規支持的命名的參數現在...您的例子並不在我的Groovy的2.0.6 – Will

+0

您正在工作(部分)右 - 我已經更新了我的問題。部分原因是我的例子不對,但groovy支持命名參數。 http://mrhaki.blogspot.de/2009/09/groovy-goodness-named-parameters-are.html - 嘿,我想這是我的問題的解決方案... – rdmueller

回答

23

也許我錯過了一些東西,但我不認爲Groovy已經命名了參數。有discussionsproposals,但我不知道任何官方。

對於您的情況,我認爲地圖傳播可能幫助,但不是在任何情況下。一旦獲得值,它遵循其中的地圖值聲明的順序:

def test(String a, String b) { "a=$a, b=$b" } 
def test(Map m) { test m*.value } 

assert test(a: "aa", b:"bb") == "a=aa, b=bb" 
assert test(b: "aa", a:"bb") != "a=aa, b=bb" // should be false :-(
assert test(b: "ccc", a:"ddd") == "a=ddd, b=ccc" // should have worked :-(

對於類,我建議Groovy's as operator

@groovy.transform.CompileStatic 
class Spread { 
    class Person { 
    String name 
    BigDecimal height 
    } 

    def method(Person p) { 
    "Name: ${p.name}, height: ${p.height}" 
    } 

    def method(Map m) { method m as Person } 

    static main(String[] args) { 
    assert new Spread().method(name: "John", height: 1.80) == 
     "Name: John, height: 1.80" 
    } 
} 
+0

太棒了!那是我想要的,但是我錯過了''價值'在'*。價值'!所以這是我原來的問題的解決方案︰'def test(String a,String b){} \ n test([a:'1',b:'2'] *。value);' – rdmueller

+5

我是不完全確定,但我想這個答案已經過時了。查看@Tom的答案。 – ben

26

不應該調用該方法是test(a:'1', b:'2');而不是test([a:'1',b:'2']);

請檢查命名參數here

+1

看起來這兩個符號都是有效的...... – rdmueller

+2

+1爲鏈接 – Will

+2

鏈接已死:-(這是[新鏈接](http://docs.groovy-lang.org/latest/html/documentation/ #_named_arguments):-) – Craig

5

感謝名單向Will P的評論,我發現它適合我的問題的解決方案:

如果我定義一個參數沒有一個類型,我可以在所有種類型,其中包含HashMap通過。和Groovy變成像a:'h',b:'i'構建自動地進入一個HashMap

def test(myParams, Integer i) { 
    return myParams.a + myParams.b 
} 

assert test(a:'h',b:'i',5) == test(b:'i',a:'h',5) 
assert test([a:'h',b:'i'],5) == test(b:'i',a:'h',5) 
test('h','i',5); //still throws an exception 

這樣一來,我可以使用單一的命名參數,但可以使用地圖呢!

+1

我以爲你在尋找類似python命名參數的東西(http://davedash.com/2007/12/21/python-named-arguments-pure-genius/)。很高興你找到了你的解決方案,無論如何:-) – Will

4

命名參數支持非常靈活,但文檔有點薄。以下是我發現的一些規則。 請注意,我想是的參數(在方法中聲明)和args用戶明確的(傳遞給方法調用)

  • 地圖參數首先必須先聲明。 這是最大的一個。並不明顯。
  • 你並不需要一個完整的地圖將在指定參數時,只需地圖元素 即(a: "aa")足夠好,你不需要([a: "aa"])
  • 你可以混合排序,名ARGS(未命名)指定參數時,只要 作爲有序參數保持與參數 相同的順序填充
  • 您可以使用常規有序參數散佈命名的參數。 這很酷,但有序的參數必須在, 以及訂單。
  • 您甚至可以在同一個 方法簽名使用可選的命令參數(參見下面的例子x
  • 你可以給地圖參數默認爲空地圖args=[:]使 命名ARGS可選的,但是這並不工作得很好,如果你有 其他可選參數(參見下面的例子最後)

下面是一些例子: 】這個params不需要鍵入,但我已經添加類型的清晰度。

// 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:s 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:s 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:s 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:s 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)