Ruby ищет переменную класса в объекте вместо определенного класса

Эта часть работает:

 class Example1
   @@var1= "var1 in the Example1"
   def get_var1
     @@var1
   end
 end

 example1 = Example1.new
 example1.get_var1
 # => "var1 in the Example1"

но если я попробую собственный класс:

def example1.get_var1
  @@var1
end

example1.get_var1
# NameError: uninitialized class variable @@var1 in Object
# from (pry):128:in `get_var1'

Руби выглядит @@var1 в Object вместо Example.

Я тестировал этот код в Ruby 1.9.3 и 2.0 с тем же результатом.

Почему это происходит?
Во-вторых, можно ли это отключить (чтобы example.get_var1 не искал переменные класса в Объекте)?


person Darek Nędza    schedule 01.07.2014    source источник
comment
Официальный термин: одиночный класс. .   -  person Max    schedule 01.07.2014
comment
@Max Спасибо, вы правы, однако собственный класс или метакласс широко используются в сообществе Ruby, а что касается тегов, singleton используется для шаблона Singleton. Так что я не вижу здесь проблем.   -  person Darek Nędza    schedule 01.07.2014
comment
Верно, но я думаю, что эти термины в значительной степени являются изобретениями до Ruby 1.9, когда был добавлен Object#singleton_class. Меня очень огорчает, как много людей, которых я вижу, все еще используют def metaclass; class << self; self; end; end, когда у нас так долго было правильное имя и метод для него.   -  person Max    schedule 01.07.2014


Ответы (1)


Похоже, что лексическая область видимости для поиска переменных класса довольно дурацкая. Насколько я могу судить, потому что ты не внутри

class Example1
end

block, ruby ​​ищет @@var не в вашем классе, а в Object. Если вы хотите это явно из своего класса, вы можете сделать:

def example1.get_var
    self.class.class_variable_get(:@@var1)
end

Я наткнулся на https://www.ruby-forum.com/topic/1228428 во время поиск ответа. Они говорят о 1.8.7, но, похоже, это относится и к более поздним версиям.

person Some Guy    schedule 01.07.2014
comment
Я согласен. Определение метода Singleton ограничено лексически, а окружающий класс в этом примере — Object. Это такое же поведение, как повторное открытие класса. Если вам нужен прямой доступ к переменным класса-предка, просто оберните одноэлементное определение внутри области родительского класса или используйте косвенное class_variable_get, как предлагает SomeGuy. - person David Unric; 01.07.2014