6

Вопрос по ruby – Доступ к константе

Почему я не могу получить доступ к B? в последующем от "A"; а может из основного окружения? module A; end A.instance_eval{B=1} B #=> 1 A::B #=> uninitialized

@ JoshLee41 Ruby1.9.3

от sawa

Какая версия Ruby?<a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/181646" rel="nofollow noreferrer">blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/181646</a> <a href="http://stackoverflow.com/questions/3015947/ruby-how-does-constant-lookup-work-in-instance-eval-class-eval" title="ruby how does constant lookup work in instance eval class eval">stackoverflow.com/questions/3015947/&#x2026;</a>

от Josh Lee

4 ответа

4

Отдокументацияinstance_eval (выделение мое):

Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables.

Здесь больше ничего не делается. В частности, константное присвоение выполняется в окружающем контексте блока. Заметим:

irb(main):001:0> module A
irb(main):002:1>   module B; end
irb(main):003:1>   B.instance_eval { C = 1 }
irb(main):004:1> end
=> 1
irb(main):006:0> A::C
=> 1
4

Because . . .

, , , Константы, которые не определены в классе или модуле, имеют глобальную область видимости.

Для определения константы важна лексическая область действия, а не текущий получатель или значениеself.

3

Идиоматический способ сделать это будет

 A.const_set(:B, 1)
 A::B #=> 1

Что касается того, почему это не работает, в Ruby 1.8 и 1.9.2+ (в 1.9.1 это было не так), постоянный поиск ограничен лексической областью. Я нашел хорошийСообщение блога с объяснением. Цитировать:

Note that these rules apply to constant definition as well as lookup. In 1.8 and 1.9.2, a constant defined in a class_evaluated block will be defined in the enclosing lexical scope, rather than the scope of the receiver.

То же самое относится и кinstance_eval.

1

module A; end
A.class_eval{B=1}
B # Undefined
A::B # 1

Что касается того, почему это работает, я не совсем уверен. Я иногда использую метапрограммирование таким образом, когда создаю очень мета-фреймворки, такие как Малый Собственный Коллайдер, но не в повседневной работе.

Похожие вопросы