Обновление "it" внутри закрытия Groovy

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

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

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

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

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

Спасибо.

Ответ 1

Цикл

Groovy each - это просто итератор, и поэтому он не влияет на коллекцию, на которой он работает, и не возвращает свое значение. Это в основном эквивалентно Java "advanced for loop (for-each)", только с удобством динамического ввода и неявной переменной цикла (it). Хотя it можно изменить, это тщетное предприятие, так как вы просто будете менять ссылку на исходное значение, а не на само значение. Подробнее см. этот вопрос.

Когда вам нужно каким-либо образом изменить каждый элемент в коллекции, идиоматическим решением Groovy (Grails) является использование метода 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.

Кроме того, блог Ted Naleid содержит несколько приятных примеров соответствия шаблонов Groovy, которые могут оказаться полезными.

Edit Вот несколько способов, с помощью которых вы могли бы сокращать решение, которое вы отправили:

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

или

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

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

youtubeLinks = youtubeLinks.join('\n').replaceAll(/.*\?v=/, '').split()

Ответ 2

Вы были правы, это оказалось как

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

Спасибо, Northover.