2012-12-22 10 views
33

mam metodanazwanych parametrów

def test(String a, String b) { } 

i chciałbym nazwać to z dynamicznego parametru mapie. Zawsze jednak, że

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

a także

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

zadziała. ale tak nie jest. Zapamiętałem więc the spread operator, ale nie mogę go uruchomić ....

Czy istnieje sposób na wywołanie metody podobnej do powyższej z jakąś mapą jako parametrem zamiast pojedynczych parametrów?

+1

nie byłem świadomy Groovy obsługiwane nazwane parametry w tej chwili ... Twój przykład nie działa w moim groove-2.0.6 – Will

+0

Twoje są (częściowo) w prawo - Mam aktualizowane na moje pytanie. Częściowo dlatego, że mój przykład jest błędny, ale groovy obsługuje nazwane parametry. http://mrhaki.blogspot.de/2009/09/groovy-goodness-named-parameters-are.html - hej, myślę, że to jest odpowiedź na moje pytanie ... – rdmueller

Odpowiedz

23

Może coś przeoczyłem, ale nie sądzę, że Groovy nazwał parametry właśnie teraz. Są discussions i proposals, ale nie jestem świadomy niczego oficjalnego.

Dla Twojej sprawy, myślę, że mapa rozprzestrzenia się może pomoc, ale nie w każdym przypadku. Po uzyskaniu wartości, wynika kolejność, w którym wartości map zostały oświadczył:

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

na zajęcia, mogę zasugerować 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

świetnie! To było dokładnie to, czego szukałem, ale brakowało mi 'value'in' * .value'! To jest więc odpowiedź na moje oryginalne pytanie: test def: (String a, String b) {} \ n test ([a: "1 ', b:" 2'] *. Wartość); " – rdmueller

+5

Jestem nie jestem całkowicie pewien, ale myślę, że ta odpowiedź jest nieaktualna. Zobacz odpowiedź z @Tom. – ben

26

nie powinno być wywołanie metody test(a:'1', b:'2'); zamiast test([a:'1',b:'2']);?

Proszę sprawdzić o nazwie Argumentyhere.

+1

Wygląda na to, że oba oznaczenia są prawidłowe ... – rdmueller

+2

+1 dla linku – Will

+2

Link jest martwy :-(Oto [nowy link] (http://docs.groovy-lang.org/latest/html/documentation/ #_named_arguments) :-) – Craig

5

thanx z komentarzem Will P, znalazłem rozwiązanie, które pasuje do mojego problemu:

gdybym zdefiniowanie jednego parametru bez typu, można przekazać w różnego rodzaju typów, w tym hashMaps. I porywające okazuje konstrukt jak a:'h',b:'i' automagicznie w 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 

ten sposób można używać pojedynczych parametrów nazwanych, ale można korzystać z mapy też!

+1

Myślałem, że szukasz czegoś podobnego do parametrów o nazwie Pythona (http://davedash.com/2007/12/21/python-named-arguments-pure-genius/). Cieszę się, że znalazłeś rozwiązanie, mimo wszystko :-) – Will

4

Obsługa nazwanych parametrów jest dość elastyczna, ale dokumenty są trochę cienkie. Oto niektóre zasady, które odkryłem. Zauważ, że staram się być jednoznaczne w użytkownika (deklarowanych parametrów w metodzie) i args (przekazany do wywołania metody)

  • Parametr Mapa najpierw muszą być zadeklarowane jako pierwszy. To jest wielki. I nie oczywiste.
  • Nie musisz pełną mapę w swoich argumentach, tylko odwzorować elementy tj (a: "aa") jest wystarczająco dobry, nie trzeba ([a: "aa"])
  • można mieszać uporządkowane (nienazwanych) args z nazwy args, tak długo jak zamówione argumenty pozostają w tej samej kolejności, co parametry , które wypełniają
  • Istnieje możliwość przeplatania nazwanych argów z regularnymi uporządkowanymi argami. To jest całkiem fajne, ale znowu zamówione argumenty muszą być w, również, zamówienie.
  • Można nawet użyć opcjonalnych zamówionych parametrów w tym samym metody podpisu (patrz x w poniższych przykładach)
  • można dać parametr mapie domyślnie pusta mapa args=[:] podejmowania nazwany argumenty opcjonalne, ale to nie robi działa dobrze, jeśli masz inne parametry opcjonalne (patrz poniżej ostatnie przykłady)

Oto kilka przykładów: params nie muszą być wpisane, ale dodałem typy dla jasności.

// 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) 
Powiązane problemy