Вот что я пытаюсь сделать:
class Foo; end
Foo.class_exec do
class_variable_set(:@@x, 42)
def get
@@x # runtime error here!
end
end
puts Foo.new.get
Я получаю (Ruby 3.2.1):
$ ruby a.rb
a.rb:6:in `get': class variable access from toplevel (RuntimeError)
from a.rb:10:in `<main>'
Как мне прочитать это @@x
, которое я только что установил?
Есть class_variable_get , но поскольку это метод Module
, вам нужно вызвать его в классе или singleton_class получателя:
Foo.class_exec do
class_variable_set(:@@x, 42)
def get
self.class.class_variable_get(:@@x)
# or
# singleton_class_variable_get(:@@x)
end
end
Альтернативно, в Ruby вполне нормально повторно открыть класс:
class Foo; end
class Foo
@@x = 42
def get
@@x
end
end
Обратите внимание, что обычно не рекомендуется использовать переменные класса из-за их неожиданного поведения при наследовании. См. Почему использование переменной класса в Ruby считается «запахом кода»?
@Алекс, это похоже на Foo.class_exec { Bar = 123 }
, который устанавливает константу верхнего уровня Bar
вместо Foo::Bar
.
теперь это имеет такой большой смысл. он объясняет поведение переменных класса лучше, чем сравнение их с переменными экземпляра: объясняет наследование, почему они доступны из методов экземпляра и класса, даже объясняет, почему это запах кода (использование констант в качестве переменных). возможно, стоит ответить здесь stackoverflow.com/questions/15773552/…
@Алекс довольно много общего, но есть и различия. Константы имеют лексическую область действия (вложенность), тогда как переменные класса имеют динамическую область действия (наследование).
поэтому использование
@@x
просто игнорирует контекстclass_exec
. это будет ошибкой?