2013-03-13 1 views
4

Groovy собирает все именованные параметры в карту и передает его в метод в качестве первого параметра. Это кажется аккуратным, но, пытаясь заставить его работать, кажется непригодным.Параметры Groovy, вызываемые параметрами, приводят к назначению параметров для переключения - каким-либо образом вокруг этого?

Так что вопрос является способом, как это:

def method(paramMap, specificVar1 = 7, specificVar2 = 14) 

при вызове этого метода с чем-то вроде этого:

method(12, extraValue: "hello") 

вы получите довольно много, что вы ожидаете:

assert 12 == specificVar1 
assert 14 == specificVar2 
assert [extraValue:"hello"] == paramMap 

не плохо, имеет смысл. Проблема заключается в том, если предположить, что Map PARAMS являются необязательными, то вы можете в конечном итоге со значениями как это:

method(12) 
assert paramMap == 12 
assert specificVar1 == 7 // default values 
assert specificVar2 == 14 

Это скаляр должен был пойти в specificVar - не карты. Если я специально тип карты в методе:

def method(Map paramMap, specificVar1 = 7, specificVar2 = 14) 

затем method(12, extraValue: "hello") работает так же, как это было раньше, но method(12) бросает ClassCastException. Это просто не представляется возможным. Есть ли способ сделать это Map «липким», чтобы он просто был пустым, если нет параметров Map?

+0

Bill K, обновленный мой ответ с очень простым решением. Надеюсь, поможет. – Will

ответ

11

Установка значений по умолчанию для параметров создает перегруженные методы с комбинациями, сделанными слева направо, поэтому трудно сделать method(12), а также иметь возможность передавать записи в карты.

Ваш метод def method(paramMap, specificVar1=7, specificVar2=14) будет генерировать следующие методы:

Object Maps.method(java.lang.Object) 
Object Maps.method(java.lang.Object,java.lang.Object) 
Object Maps.method(java.lang.Object,java.lang.Object,java.lang.Object) 

и полностью набранный метод с картой парам:

def method3(Map paramMap=[:], Integer specificVar1=7, Integer specificVar2=14) { 
} 

будет генерировать следующие методы:

Object Maps.method3() 
Object Maps.method3(java.util.Map) 
Object Maps.method3(java.util.Map,java.lang.Integer) 
Object Maps.method3(java.util.Map,java.lang.Integer,java.lang.Integer) 

(Нет подходящего метода для method(12)).

Кроме того, записи, переданные методу, будут собраны и вставлены в первую карту . Следующий метод:

def method4(Integer specificVar1=7, Integer specificVar2=14, Map map=[:]) { 

Формирует:

Object Maps.method4() 
Object Maps.method4(java.lang.Integer) 
Object Maps.method4(java.lang.Integer,java.lang.Integer) 
Object Maps.method4(java.lang.Integer,java.lang.Integer,java.util.Map) 

Таким образом, method4 12, a:'b' терпит неудачу с:

No signature of method: Maps.method4() is applicable for argument types: 
    (java.util.LinkedHashMap, java.lang.Integer) values: [[a:b], 12] 

Так что, нет, я не думаю, что вы можете делать то, что вы хотите с помощью карты :-).


Решение 1:

Если вы находитесь в чистом динамическом решении, вы можете использовать один аргумент карты:

def method5(Map map) { 
    def specificVar1 = map.specificVar1 ?: 7 
    def specificVar2 = map.specificVar2 ?: 14 
} 

Решение 2 (обновлено):

Вы можете создать класс для представления параметров. Использование карты, подлежащей принуждению к объекту, статически компилируемо и синтаксический сахар для него.

@groovy.transform.CompileStatic 
class Maps { 
    def method6(Foo foo) { "$foo.params, $foo.specificVar1, $foo.specificVar2" } 
    def method6(Map map) { method6 map as Foo } 

    static main(args) { 
    def maps = new Maps() 

    assert maps.method6(params: [a: 'b', c: 'd'], specificVar1: 40) == 
     "[a:b, c:d], 40, 14" 

    assert maps.method6(new Foo(params: [a: 'b', c: 'd'], specificVar2: 21)) == 
     "[a:b, c:d], 7, 21" 
    } 
} 

class Foo { 
    def specificVar1 = 7, specificVar2 = 14, params = [:] 
} 

Раствор 3:

перегруженный метод.

def method6(Map paramMap, Integer specificVar1=7, Integer specificVar2=14) { 
    "$paramMap, $specificVar1, $specificVar2" 
} 

def method6(Integer specificVar1=7, Integer specificVar2=14) { 
    method6 [:], specificVar1, specificVar2 
} 


assert method6(12) == "[:], 12, 14" 
assert method6() == "[:], 7, 14" 
assert method6(a:'b', 18) == "[a:b], 18, 14" 
assert method6(18, a:'b', 27) == "[a:b], 18, 27" 
assert method6(90, 100) == "[:], 90, 100" 
assert method6(a:'b', 140, c:'d') == "[a:b, c:d], 140, 14" 

карта версия метод не может иметь параметр по умолчанию, в противном случае оба метода сгенерирует method6 и без параметров те будут конфликтовать.

+0

Хороший анализ. Я склоняюсь к единственному решению карты, но он делает его немного более жестким (тип безопасности, простой список параметров ...), но это может быть лучшее, что мы можем сделать в текущем groovy –

+0

Это фантастика. Мне нравится решение 3! Большое спасибо за ваше время и настойчивость @Will. Бьюсь об заклад, существует способ генерации сигнатуры пересылки из аннотации и методаMissing (эти классы уже расширяют базовый класс, поэтому я уверен, что смогу заставить его работать точно так, как я хочу, с помощью трюка). Хотелось бы, чтобы был способ вознаградить дополнительный пост за это - Может быть, я могу с щедростью, мне нужно заглянуть в это! –

+0

Я рад, что это помогло :-) – Will

Смежные вопросы