Например, если мы
def c=(foo) p "hello" end c = 3 c=(3)
и "привет" не будет напечатан. Я знаю, что это может быть вызвано self.c = 3 но почему? и каким образом это может быть вызвано?
self.c = 3
c = 3 (и c = (3), что ему полностью соответствует) всегда интерпретируется как присвоение локальной переменной. Вы могли бы сказать, что его следует интерпретировать как присвоение локальной переменной, только если метод c= не определен для себя, но есть различные проблемы с этим:
c = 3
c = (3)
c=
Как минимум, МРТ должно знать во время анализа, какие локальные переменные определены в данной области. Однако во время разбора неизвестно, определен данный метод или нет. Таким образом, ruby не может знать, определяет ли c = 3 переменную c или вызывает метод c= до времени выполнения, что означает, что он не будет знать, определена ли локальная переменная c во время анализа. Это означает, что MRI потребуется изменить способ обработки локальных переменных в синтаксическом анализаторе, чтобы он работал так, как вы этого хотите.
c
Невозможно определить локальную переменную с именем c, если метод c= уже определен. Вы можете сказать, что все в порядке, потому что локальные переменные и методы с одинаковыми именами в любом случае сбивают с толку. Однако рассмотрим случай, когда вы определяете method_missing, так что foo= определяется для каждого возможного foo (как, например, для OpenStruct s). В этом случае было бы невозможно определить локальные переменные вообще.
method_missing
foo=
OpenStruct
Вы не можете точно сказать, реагирует ли объект на c= без его запуска, потому что он может быть обработан method_missing. Так что все это на самом деле было бы неразрешимо.
Поскольку локальные переменные имеют приоритет над ранее определенными методами / переменными с тем же именем.В этом случае вам необходимо указать «self», чтобы c не интерпретировалось как объявление / присвоение локальной переменной.
Ruby вызывает этот метод только в том случае, если код не может быть интерпретирован как присвоение переменной. Нет лучшего способа форсировать вызов метода.
self.c = 1 send(:c=, 1) __send__(:c=, 1) method(:c=).call(1) method(:c=)[1]