ruby: как ссылаться на @foo внутри другого объекта? - PullRequest
1 голос
/ 29 января 2009

В ruby ​​я хочу сделать примерно следующее и распечатать "изменено":

class Whatever
  def change_foo
    @foo="changed"
  end
end

@foo = "original"
o = Whatever.new
o.change_foo
puts "it changed" if @foo == "changed"
puts "it did not change" if @foo == "original"

Проблема, конечно, в том, что внутри Whatever, @foo принадлежит экземпляру Whatever.

Есть ли способ заставить change_foo изменить "глобальный" foo? Другой способ задать это может быть: «на какой объект я могу ссылаться, который« владеет »@foo?».

Мне не нужны такие решения, как «использовать глобальную переменную» или «использовать переменную класса» или «передать @foo в change_foo». Я специально спрашиваю о вышеописанном сценарии, где у меня нет контроля ни над исходной переменной, ни над тем, как вызывается change_foo.

Я нашел обходной путь, в котором я передаю ссылку на глобальный объект во время строительства, но я не без ума от этого, так как для этого требуется, чтобы я создал все, что нужно, в нужном объеме.

class Whatever
  def initialize(main)
    @main = main
  end

  def change_foo
    @main.instance_variable_set("@foo","changed")
  end
end
o = Whatever.new(self)

Ответы [ 4 ]

1 голос
/ 01 сентября 2009

Поздно для вечеринки, но вы можете передать текущий контекст методу, а затем оценить операции с переменной экземпляра в этом конкретном контексте:

class Whatever
  def changeFoo(context)
    eval %q( @foo="changed" ), context
  end
end
@foo = "original"
o = Whatever.new()
o.changeFoo(binding)
puts "it changed" if @foo == "changed"
puts "it did not change" if @foo == "original"

# => it changed
1 голос
/ 29 января 2009

Я знаю, что это ответ, который вам не нужен, но из вашего описания вам действительно следует использовать переменную класса. Кроме того, невозможно найти «владельца» переменной, потому что все строки с определенным содержимым (например, «оригинал») неразличимы - нет записи о том, откуда она взялась (если, конечно, @foo действительно не является пользовательским объект, в котором можно хранить ссылку на родителя).

0 голосов
/ 29 января 2009

Я чувствую себя немного глупо, когда делаю это, но все равно буду это терпеть. Похоже, у самбо правильная идея. Я не знал об этом модуле ObjectSpace. Сладкое.

Я завернул его в модуль.

module What

  @foo = 'bar'

  class Whatever
    def change_foo
      What.instance_variable_set(:@foo, "changed")
    end
  end

end


w = What::Whatever.new

p What.instance_variable_get(:@foo)    
# >> "bar"

w.change_foo

p What.instance_variable_get(:@foo)
# >> "changed"
0 голосов
/ 29 января 2009

Почему вы когда-нибудь захотите сделать что-то подобное, я не знаю ... вам не следует определять переменную экземпляра для вашего корневого объекта, и глобальных значений следует избегать любой ценой.

Это показывает, каким образом вы можете достичь этого. Вы можете избежать использования объектного пространства, просто определив $ self = self в верхней части вашего скрипта.

В любом случае, вот пример рабочего кода, сделайте себе одолжение и не используйте его

class Whatever
    def changeFoo
        @foo="changed"
    end

    def changeFoo2(o)
      o.instance_variable_set('@foo', 'changed')
    end

    def changeFoo3
      ObjectSpace.each_object do |o| 
        if o.instance_of? Object and o.instance_variables.include?("@foo")
          o.instance_variable_set('@foo', 'changed')
        end
      end
    end
end
@foo = "original"
o = Whatever.new()
o.changeFoo()
puts "it changed" if @foo == "changed"
puts "it did not change" if @foo == "original"

o.changeFoo2(self) 
puts "it changed" if @foo == "changed"
puts "it did not change" if @foo == "original"

@foo = "original" 

o.changeFoo3() 
puts "it changed" if @foo == "changed"
puts "it did not change" if @foo == "original"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...