Почему переменная с локальной областью действия, которая не была определена, ссылается на переменную экземпляра с тем же именем? - PullRequest
2 голосов
/ 18 августа 2011

Я обнаружил странную ошибку в моем коде, которая обнаружила интересное поведение ruby. Надеюсь, кто-то может объяснить, почему он так себя ведет.

У меня был класс с переменной экземпляра @foo и метод, который ссылался на локальную переменную scoo. Я рефакторил часть метода, случайно оставив ссылку на foo; переменная больше не определена в области видимости. Вместо этого он указывал на @foo. Изменение foo внесло изменения в @foo и наоборот.

Упрощенная версия: РЕДАКТИРОВАТЬ: добавлено ImOutOfNames.

class ImOutOfNames
    attr_accessor :foo # the culprit!
end

class Bar < ImOutOfNames
    def initialize
        @foo = "that is a tasty burger"
    end

    def bar_method_1
        foo = "Come on Yolanda, whats Fonzie like?"
        bar_method_2
    end

    def bar_method_2
        puts foo
    end
end

И выходные данные bar_method_1 и bar_method_2 были "это вкусный гамбургер". Я ожидал, что произойдет ошибка, например, выполнение приведенного выше кода приводит к

NameError: undefined local variable or method

Я даже пригласил более старшего разработчика, и он был несколько озадачен и подтвердил поведение.

Это ожидаемое поведение, и я неправильно понял, как работает @variables, или что-то не так?

Ответы [ 2 ]

4 голосов
/ 18 августа 2011

Ваш предыдущий ошибочный код, вероятно, в определении attr_accessor , который создал метод foo , который получил доступ к вашей переменной экземпляра,

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

class Bar

  attr_accessor :foo

  def initialize
    @foo = "that is a tasty burger"
  end

  def bar_method_1
    foo = "Come on Yolanda, whats Fonzie like?"
    bar_method_2
  end

  def bar_method_2
    puts foo
  end
end

Вызов attr_accessor определяет два метода в вашем объекте;

def foo
  @foo
end

def foo=(value)
  @foo = value
end

Таким образом, в вашем случае, когда локальная переменная не была определена, метод использовался, но, поскольку вы не вызывали attr_accessor, в этом примере, который вы опубликовали, метод не был определен, и не было локальной переменной для bar_method_2 поэтому вызов не удался.

0 голосов
/ 18 августа 2011

У вас есть аксессор attr для вашей переменной экземпляра @foo? Это может произойти одним из способов.

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

self.method(:foo)

или даже если оно определено с

defined? foo

Использование среды исполнения ruby ​​в ваших интересах определенно уменьшает мистику и магическую природу некоторого кода.

...