Обновление "это" внутри Groovy замыкания - PullRequest
10 голосов
/ 17 января 2011

У меня есть класс домена, который представляет собой просто список строк (youtubeLinks).

При сохранении этих ссылок я хочу удалить идентификатор видео и сохранить его вместо всего URL-адреса, введенного на стороне пользовательского интерфейса.

Это то, что я пытаюсь (игнорируйте это регулярное выражениеимеет недостатки)

youtubeLinks.each {
 def youtubeRegex = /v=(.*)/
 def matcher = ( it =~ youtubeRegex )
 it = matcher[0][1]
}

Когда я сохраняю это, оно сохраняет первоначальное значение "оно".Есть ли способ обновить эту ссылку и сохранить ее правильно?

Спасибо.

Ответы [ 2 ]

22 голосов
/ 17 января 2011

Цикл Groovy each является просто итератором, и как таковой он не влияет на коллекцию, в которой он работает, и не возвращает свое собственное значение. Это в основном эквивалентно Java «расширенный цикл (для каждого)», только с удобством динамической типизации и неявной переменной цикла (it). Хотя it можно изменить, это бесполезное предприятие, так как вы просто изменили бы ссылку на исходное значение, а не на само значение. См. этот вопрос , чтобы узнать больше.

Когда вам нужно как-то изменить каждый элемент в коллекции, идиоматическое решение Groovy (Grails) заключается в использовании метода collect. Collect преобразует каждый элемент через предоставленное вами замыкание, в конечном итоге возвращая новую коллекцию (то есть фактически ничего не «модифицирует»).

По сути, вы, вероятно, захотите сделать что-то вроде этого:

def links = '''http://www.youtube.com/watch?v=fl6s1x9j4QQ
http://www.youtube.com/watch?v=tCvMKcNJCAY
'''

assert (links =~ /watch\?v=(.*)/).collect{match -> match[1]} == ["fl6s1x9j4QQ", "tCvMKcNJCAY"]

.. Хотя на самом деле в Groovy можно решить несколько задач.

Кроме того, В блоге Теда Нейлида есть несколько хороших примеров сопоставления с Groovy, которые могут оказаться полезными.

Редактировать Вот несколько способов, которыми вы можете сократить представленное вами решение:

youtubeLinks = youtubeLinks.collect{link -> (link =~ /\?v=(.*)$/)[0][1]}

или

youtubeLinks = youtubeLinks.collect{link -> link.replaceAll(/^.*\?v=/, "") }

или это (хотя это немного надумано)

youtubeLinks = youtubeLinks.join('\n').replaceAll(/.*\?v=/, '').split()
2 голосов
/ 17 января 2011

Вы были правы, все закончилось как

youtubeLinks = youtubeLinks.collect {
    def youtubeRegex = /v=(.*)[&]/
    def matcher = ( it =~ youtubeRegex )
    return matcher[0][1]
}

Спасибо, Север.

...