метапрограммирование доступа к локальным переменным - PullRequest
2 голосов
/ 24 октября 2010
class Foo
  def initialize
    bar = 10
  end
  fiz = 5
end

Есть ли возможность получить эти локальные значения (вне класса)?

Ответы [ 3 ]

3 голосов
/ 25 октября 2010

Локальная переменная при инициализации будет потеряна.

Вы можете получить значение fiz за пределами класса, но только после определения этого класса и записи возврата определения класса.

return_of_class_definition = (class A ; fiz = 5 ; end) присвоит значение fiz переменной.

Вы также можете использовать binding, но, конечно, это означает изменение класса, что может быть запрещено для упражнения.

class A
  bin = 15
  $binding = binding
end

p eval 'bin', $binding
2 голосов
/ 24 октября 2010

Нет. Как только локальная переменная выходит из области видимости (для бара, когда выполняется метод initialize - для fiz, когда достигнуто end определения класса), она исчезает. Никаких следов не осталось.

Пока локальная переменная все еще находится в области видимости, вы можете увидеть ее (ну, ее имя) с помощью local_variables, получить и установить ее значение с помощью eval (хотя это определенно не рекомендуется по соображениям здравого смысла), но как только она выйдет области, вот и все. Нет способа вернуть его обратно.

1 голос
/ 07 апреля 2012

В ruby ​​у нас есть то, что мы можем назвать областями видимости - места, когда программа, написанная на ruby, покидает предыдущую область видимости. Эти ворота: class, module и метод (ключевое слово def). Другими словами, после ключевого слова class, module из def в коде, который вы сразу вводите в новую область.

В ruby ​​вложенной видимости не происходит, и как только вы создадите новую область, предыдущая привязка будет заменена новым набором привязок.

Например, если вы определите следующий класс:

x = 1
class MyClass
  # you can't access to x from here
  def foo
    # ...from here too
    y = 1
    local_variables
  end
end

local_variables вызов метода вернет [:y]. Это означает, что у нас нет доступа к переменной x. Вы можете обойти эту проблему, используя методику ruby ​​ Flat Scopes . По сути, вместо определения класса с помощью ключевого слова class вы можете определить его с помощью Class.new и передать блок этому вызову. Очевидно, что блок может взять любые локальные переменные из области, где он был определен, так как это закрытие!

Наш предыдущий пример можно переписать примерно так:

x = 1
Foo = Class.new do
  define_method :foo do
    i_can_do_something_with(x)
    y = 1
    local_variables
  end
end

В этом случае local_variables вернет [:x, :y].

...