Динамические классы Ruby. Как исправить "предупреждение: доступ переменной класса из toplevel" - программирование
Подтвердить что ты не робот

Динамические классы Ruby. Как исправить "предупреждение: доступ переменной класса из toplevel"

Я пытаюсь написать программу, которая динамически определяет классы ruby ​​на основе конфигурации, считанной из файла. Я знаю, что могу использовать Class.new для этого. Вот пример программы:

x = [1,2,3]

Test = Class.new do
  @@mylist = x

  def foo
    puts @@mylist
  end
end

Test.new.foo

Когда я запускаю это, я получаю следующий вывод (работает с ruby ​​1.9.3p0):

c:/utils/test.rb:4: warning: class variable access from toplevel
c:/utils/test.rb:7: warning: class variable access from toplevel
1
2
3

Кто-нибудь знает, что вызывает эти предупреждения и как я могу избавиться от них?

Я попытался заменить строку tjhat

@@mylist = x

с этим

class_variable_set(:@@mylist, x)

Но когда я это делаю, я получаю эту ошибку:

c:/utils/test.rb:7: warning: class variable access from toplevel
c:/utils/test.rb:7:in `foo': uninitialized class variable @@mylist in Object (NameError)
        from c:/utils/test.rb:11:in `'

Спасибо заранее!

4b9b3361

Ответ 1

Чтобы удалить это предупреждение, вы должны использовать метод class_variable_set:

x = [1,2,3]

Test = Class.new do
  class_variable_set(:@@mylist, x)

  def foo
    puts @@mylist
  end
end

Ответ 2

Это не делает то, что вы думаете, что это делает. Поскольку вы не создаете класс с ключевым словом class, ваша переменная класса устанавливается на Object, а не Test. Последствия этого довольно огромны, поэтому Ruby предупреждает вас. Переменные класса разделяются между предками, а объекты обычно наследуются от Object.

Ответ 3

Вместо определения вашей переменной класса "mylist" класса при объявлении класса вы можете объявить переменные уровня класса на нем позже, как показано ниже. Показаны два разных метода. Первый работает только в 1.9, последний работает в обеих версиях, но менее идиоматичен.

x = [1,2,3]

Test = Class.new do
  def foo
    puts @@mylist
  end
end

# ruby 1.9.2
Test.class_variable_set(:@@mylist, x)   

# ruby 1.8.7
Test.class_eval {
  @@mylist = x
}

Test.new.foo