Groovy 'def' ключевое слово и проблема в Eclipse - PullRequest
0 голосов
/ 21 марта 2011

Я следую Groovy-учебнику, и есть код, подобный следующему:

def fruit = ["apple", "orange" , "pear"]    //list
def likeIt = { String fruit -> println "I like " + fruit + "s" }    //closure
fruit.each(likeIt)

Eclipse сообщает об ошибке в строке определения замыкания:

Точка разрыва строки: SimpleClosuresTest [строка: 27] В текущей области уже содержится переменная с именем fruit @ line 27, столбец 14.

Если я опускаю 'def' из 'def fruit', Eclipse не жалуется и код запускаетсяхорошо.

Может ли кто-нибудь объяснить, что происходит с областями в обоих случаях?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 21 марта 2011

первый общий обзор отличного сценария:

// file: SomeScript.groovy
x = 1
def x = 2
println x
println this.x

примерно компилируется как:

class SomeScript extends groovy.lang.Script {
  def x
  def run() {
    x = 1
    def x = 2
    println x // 2
    println this.x // 1
  }
}

в скрипте groovy (грубо говоря, в файле без объявления класса) присвоение значения неопределенной переменной интерпретируется как присвоение поля.

ваш пример пытается определить замыкание с параметром с именем fruit.
если вы определили fruit с помощью ключевого слова def, вы получите сообщение об ошибке, поскольку имя уже взято как локальная переменная, и вы не можете дублировать имя локальной переменной.
когда вы опускаете ключевое слово def, вы фактически присваиваете значение полю класса, сгенерированного для скрипта, и, таким образом, имя fruit может быть переопределено как локальная переменная.

в отношении областей, это очень похоже на Java ...
в примере вы можете видеть, что x определяется сначала как поле, а затем как переменная, локальная для метода run(). в этом нет ничего плохого, и вы можете получить доступ как к переменной, так и к полю.
но как только вы определите локальную переменную, вы не сможете создавать дубликаты.

редактировать -
Я должен был добавить это, прежде чем кто-нибудь поймет меня неправильно: перевод не совсем такой (таким образом, «примерно»). Вместо поля вы добавляете значение для привязки сценария, совсем как args для сценариев командной строки или request, session или response для groovlets.
но это гораздо более длинная история ...
хорошо, если вы действительно хотите знать, просто спросите еще раз, и я объясню это лучше

редактировать 2 - я просто не могу оставить это так, если вам когда-нибудь понадобится дополнительная информация ...

каждый скрипт Groovy имеет поле с именем binding, экземпляр groovy.lang.Binding или один из его подклассов.
эта привязка в основном карта с методами setVariable и setVariable.
когда вы опускаете ключевое слово def при назначении значения в скрипте, вы фактически вызываете метод setVariable, а когда вы делаете что-то вроде this.x, вы вызываете метод getVariable.
это на самом деле потому, что класс groovy.lang.Script переопределяет методы getProperty и setProperty, чтобы сначала вызывать эти методы. Вот почему они ведут себя как поля.
Вы могли также заметить, что с этими переменными не связан тип ... это потому, что мы имеем дело с Map внутри привязки.
стандартные скриптовые скрипты создаются с экземпляром привязки с набором args для массива параметров.
другие, например groovy.servlet.ServletBinding, определяют больше переменных и поведения, например, блокируют присвоение определенных переменных или добавляют ленивые возможности инициализации ...

тогда истинная причина ошибки заключается в том, что ... если ключевое слово def не используется, fruits не является реальной переменной. тем не менее, я считаю, что поведение несколько аналогично области.

прости за все это. я не был удовлетворен своим собственным упрощением: S

2 голосов
/ 21 марта 2011

У этого фрукта String не должно быть того же имени, что и у вашего фрукта def.(вы определяете сначала список, а затем строку с тем же именем)

def likeIt = { String fruit -> println "I like " + fruit + "s" }    

Во втором случае вы определяете тип переменной с помощью def a posteriori, поэтому она работает, но это ненасколько я знаю, хорошая практика.

Я думаю, что вам даже не нужно писать ->.В руководстве groovy говорится, что «токен -> является необязательным и может быть опущен, если ваше определение Closure принимает менее двух параметров», что имеет место в данном случае.

0 голосов
/ 21 марта 2011

Вторая строка

Фруктовая строка

снова используется то же имя переменной 'fruit'

...