In ruby I want to do roughly the following and have it print out "changed":
在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"
The problem is, of course, that inside Whatever
, @foo
belongs to an instance of Whatever
.
问题是,当然,无论如何,@ foo属于Whatever的一个实例。
Is there a way to make change_foo
change the "global" foo? Another way of asking this might be "what object can I reference that "owns" @foo
?".
有没有办法让change_foo改变“全局”foo?问这个的另一种方式可能是“我可以引用哪个对象”拥有“@foo?”。
I don't want solutions like "use a global variable" or "use a class variable" or "pass @foo
to change_foo
". I'm specifically asking about the above scenario where I have no control over the original variable nor the way that change_foo
is called.
我不想要“使用全局变量”或“使用类变量”或“将@foo传递给change_foo”等解决方案。我特别询问上面的情况,我无法控制原始变量,也没有调用change_foo的方式。
I have come up with a workaround where I pass in a reference to the global object at construction time, but I'm not crazy about it since it requires I instantiate Whatever at the proper scope.
我提出了一个解决方法,我在构造时传递对全局对象的引用,但我并不是因为它需要我在适当的范围内实例化Whatever而疯狂。
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
Late to the party, but you can pass the current context to the method, and then eval the operations on the instance variable in that specific context:
晚到派对,但您可以将当前上下文传递给方法,然后在该特定上下文中对实例变量的操作进行评估:
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
I know this is the answer you don't want, but from your description, you should really should be using a class variable. Also, it's impossible to find the "owner" of a variable because all strings with a certain content (e.g., "original") are indistinguishable - there's no record of where it came from (unless, of course, @foo is really a custom object where you can store a reference to the parent).
我知道这是你不想要的答案,但是根据你的描述,你应该真的应该使用类变量。此外,找不到变量的“所有者”是不可能的,因为具有特定内容的所有字符串(例如,“原始”)都是难以区分的 - 没有记录它来自哪里(当然,除非@foo真的是一个自定义您可以存储对父项的引用的对象)。
#3
Why you would ever want to do something like this is beyond me ... you should not be defining instance variable on your root object and globals are to be avoided at all costs.
为什么你想要做这样的事情超出了我...你不应该在你的根对象上定义实例变量,并且不惜一切代价避免全局变量。
This illustrates some ways you can achieve this. You could avoid the object space stuff by simply defining $self = self at the top of your script.
这说明了一些可以实现此目的的方法。您可以通过在脚本顶部定义$ self = self来避免使用对象空间。
Anyway here is some working sample code, do yourself a favor and don't use it
无论如何这里是一些工作示例代码,帮自己一个忙,不要使用它
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"
#4
I feel a bit silly doing this, but I'll put it up anyway. Seems like sambo has the right idea. I didn't know about that ObjectSpace module. Sweet.
我觉得这样做有点傻,但无论如何我都会把它搞砸。看起来像sambo有正确的想法。我不知道那个ObjectSpace模块。甜。
I wrapped it in a module.
我把它包装在一个模块中。
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"
#1
Late to the party, but you can pass the current context to the method, and then eval the operations on the instance variable in that specific context:
晚到派对,但您可以将当前上下文传递给方法,然后在该特定上下文中对实例变量的操作进行评估:
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
I know this is the answer you don't want, but from your description, you should really should be using a class variable. Also, it's impossible to find the "owner" of a variable because all strings with a certain content (e.g., "original") are indistinguishable - there's no record of where it came from (unless, of course, @foo is really a custom object where you can store a reference to the parent).
我知道这是你不想要的答案,但是根据你的描述,你应该真的应该使用类变量。此外,找不到变量的“所有者”是不可能的,因为具有特定内容的所有字符串(例如,“原始”)都是难以区分的 - 没有记录它来自哪里(当然,除非@foo真的是一个自定义您可以存储对父项的引用的对象)。
#3
Why you would ever want to do something like this is beyond me ... you should not be defining instance variable on your root object and globals are to be avoided at all costs.
为什么你想要做这样的事情超出了我...你不应该在你的根对象上定义实例变量,并且不惜一切代价避免全局变量。
This illustrates some ways you can achieve this. You could avoid the object space stuff by simply defining $self = self at the top of your script.
这说明了一些可以实现此目的的方法。您可以通过在脚本顶部定义$ self = self来避免使用对象空间。
Anyway here is some working sample code, do yourself a favor and don't use it
无论如何这里是一些工作示例代码,帮自己一个忙,不要使用它
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"
#4
I feel a bit silly doing this, but I'll put it up anyway. Seems like sambo has the right idea. I didn't know about that ObjectSpace module. Sweet.
我觉得这样做有点傻,但无论如何我都会把它搞砸。看起来像sambo有正确的想法。我不知道那个ObjectSpace模块。甜。
I wrapped it in a module.
我把它包装在一个模块中。
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"