2012-12-22 18 views
33

Ich habe MethodeBenannte Parameter

def test(String a, String b) { } 

und ich möchte dies nennen mit einem dynamischen Parameterkarte. ich immer aber, dass

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

und auch

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

arbeiten. aber das tut es nicht. Also erinnerte ich mich an the spread operator, aber kann es nicht zum arbeiten ....

Gibt es eine Möglichkeit, eine Methode wie die oben mit einer Art Karte als Parameter anstelle von einzelnen Parametern aufzurufen?

+1

mir nicht bewusst, groovy Parameter unterstützt jetzt genannt ... Ihr Beispiel in meinem groovy-2.0.6 – Will

+0

Sie befinden sich nicht funktioniert (teilweise) Recht - ich habe meine Frage aktualisiert. Zum Teil, weil mein Beispiel falsch ist, aber groovy unterstützt benannte Parameter. http://mrhaki.blogspot.de/2009/09/groovy-goodness-named-parameters-are.html - hey, ich denke, das ist die Lösung für meine Frage ... – rdmueller

Antwort

23

Vielleicht habe ich etwas verpasst, aber ich glaube nicht, dass Groovy jetzt Parameter benannt hat. Es gibt discussions und proposals, aber mir ist nichts offiziell bekannt.

Für Ihren Fall, ich denke, die Karte verteilt kann helfen, aber nicht in jedem Fall. Auf die Werte bekommen, so folgt die Reihenfolge, in der die Kartenwerte deklariert wurden:

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 :-(

Für Klassen, kann ich vorschlagen 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

großartig! Das war genau das, was ich suchte, aber ich vermisste den "Wert" in '* .value'! Also das ist die Lösung meiner ursprünglichen Frage: 'def test (String a, String b) {} \ n test ([a: '1', b: '2'] *. Wert);' – rdmueller

+5

Ich bin nicht ganz sicher, aber ich denke, diese Antwort ist veraltet. Siehe die Antwort von @Tom. – ben

26

Sollte nicht der Aufruf der Methode test(a:'1', b:'2'); statt test([a:'1',b:'2']);?

Bitte überprüfen Sie Benannte Argumentehere.

+1

Es scheint, dass beide Notationen gültig sind ... – rdmueller

+2

+1 für den Link – Will

+2

Der Link ist tot :-(Hier ist der [neue Link] (http://docs.groovy-lang.org/latest/html/documentation/ #_named_arguments) :-) – Craig

5

thanx zum Kommentar von Will P habe ich eine Lösung gefunden, die mein Problem passt:

wenn ich einen Parameter ohne Typ definieren, kann ich in allen möglichen Arten passieren, einschließlich HashMaps. Und groovy dreht ein Konstrukt wie a:'h',b:'i' automagically in eine 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 

Auf diese Weise kann ich einzelne benannte Parameter verwenden, kann aber eine Karte verwenden!

+1

Ich dachte, Sie suchten nach etwas wie python benannte Parameter (http://davedash.com/2007/12/21/python-named-arguments-pure-genius/). Froh, dass du deine Lösung gefunden hast :-) – Will

4

Die Unterstützung benannter Parameter ist ziemlich flexibel, aber die Dokumente sind ein wenig dünn. Hier sind einige der Regeln, die ich entdeckt habe. Bitte beachte, dass ich versuche, eindeutig in den Anwender-Parameter (in der Methode deklariert) und args (zum Methodenaufruf übergeben)

  • Der Map-Parameter zunächst zuerst deklariert werden müssen. Das ist der Große. Und nicht offensichtlich.
  • Sie keine vollständige Karte in Ihrem args benötigen, nur Elemente Karte dh (a: "aa") gut genug ist, brauchen Sie nicht ([a: "aa"])
  • Sie können mit dem Namen args, so lange als die bestellte (unbenannt) args mix geordnete Argumente bleiben in der gleichen Reihenfolge wie die Parameter Sie füllen
  • Sie können benannte Args mit regulären geordneten Args interspersen. Das ist ziemlich cool, aber wieder die bestellten Args müssen in, gut, um.
  • Sie können auch optional bestellt Parameter in der gleichen Methodensignatur (siehe x in den Beispielen unten) verwenden
  • Sie die Karte Parameter die eine Standard leeren Karte args=[:] machen args optional genannt geben kann, aber dies nicht gut funktionieren, wenn Sie weitere optionale Parameter (siehe letzte Beispiele unten)

Hier sind einige Beispiele haben: Die params nicht brauchen werden eingegeben, aber ich habe Typen für Klarheit hinzugefügt.

// 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) 
Verwandte Themen