Почему эта переменная исчезает в структуре? - PullRequest
1 голос
/ 25 марта 2012

Может быть, я просто недостаточно знаю о структурах и использовал их вслепую, но приведенный ниже результат кажется мне иррациональным.

class VarTest < Struct.new(:email)
  def perform
    puts "Start: #{email}"
    if email == "nothing"
      email = "bad email"
    end
    puts "End: #{email}"
  end
end
VarTest.new("test@example.com").perform

Неожиданный вывод:

Start: test@example.com
End:

Если я изменю код на:

class VarTest < Struct.new(:email)
  def perform
    e = email
    puts "Start: #{e}"
    if e == "nothing"
      e = "bad email"
    end
    puts "End: #{e}"
  end
end

VarTest.new("test@example.com").perform

Получаем ожидаемый результат:

Start: test@example.com
End: test@example.com

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

Спасибо.

1 Ответ

4 голосов
/ 25 марта 2012

Если вы замените email = "bad email" на self.email = "bad email", он будет работать как положено. Это всегда верно при использовании сеттеров.

Причина проста: когда Ruby встречает голое слово, он пытается определить его как локальную переменную. Если его нет, он попытается вызвать метод с таким именем. Внутри тела класса self является неявным получателем, поэтому читатели просто работают. Теперь для писателя есть проблема. Если вы напишите что-то вроде foo = "bar", Ruby создаст новую локальную переменную, поэтому вам нужно сделать получатель явным.

Этот случай немного сложнее: if email == "nothing" использует геттер. Тем не менее, синтаксический анализатор все еще видит email = "bad email", а для локальной переменной email будет установлено значение nil. Это всегда происходит, когда синтаксический анализатор видит голое слово как LHS назначения. Это локальное значение nil делает его похожим, что значение email исчезает (что можно проверить, изменив только последний puts на puts "End: #{self.email}").

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...