ruby:如何在另一个对象中引用@foo?

时间:2009-01-29 00:13:41

标签: ruby

在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 个答案:

答案 0 :(得分:1)

我知道这是你不想要的答案,但是根据你的描述,你应该真的应该使用一个类变量。此外,找不到变量的“所有者”是不可能的,因为具有特定内容的所有字符串(例如,“原始”)都是无法区分的 - 没有记录它来自哪里(当然,除非@foo真的是一个自定义您可以存储对父项的引用的对象。)

答案 1 :(得分:1)

派对晚了,但您可以将当前上下文传递给该方法,然后在该特定上下文中对该实例变量的操作进行评估:

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

答案 2 :(得分:0)

为什么你想要做这样的事情超出我的范围......你不应该在你的根对象上定义实例变量,并且不惜一切代价避免全局变量。

这说明了实现这一目标的一些方法。您可以通过在脚本顶部定义$ 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"

答案 3 :(得分:0)

我觉得这样做有点傻,但无论如何我都会把它搞砸。看起来像sambo有​​正确的想法。我不知道那个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"