如何从singleton方法访问实例变量?
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
def item.singl
[self, @a].join(" + ")
end
item
end
end
test = Test.new("cao")
item = test.item
item.singl
#=> ... @a is nil
答案 0 :(得分:6)
尝试使用define_method。 Def将您置于新范围内。
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
item.singleton_class.send(:define_method, :singl) do
[self, @a].join(" + ")
end
item
end
end
test = Test.new("cao")
item = test.item
item.singl #=> "hola + "
在你的例子中,你仍然有问题,在字符串的单例类中没有定义@a。这主要是因为此上下文中的self是字符串实例,而不是存在@a
的测试实例。要解决此问题,您可以将实例变量重新绑定到其他位置,但这可能不是您正在寻找的行为。您还可以在新的单例类中设置实例变量。
例如,
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
new_self = self
item.singleton_class.send(:define_method, :singl) do
[self, new_self.instance_variable_get(:@a)].join(" + ")
end
item
end
end
test = Test.new("cao")
item = test.item
item.singl
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
item.singleton_class.send(:define_method, :singl) do
[self, @a].join(" + ")
end
item.singleton_class.send(:define_method, :set) do
@a = "cao"
end
item
end
end
test = Test.new("cao")
item = test.item
item.set
item.singl
重要的是要注意两种方法之间的差异。在第一种方法中,我们通过原始对象保留对原始实例变量的引用。在第二种方法中,我们创建一个新的实例变量,绑定在新的单例类下,包含原始测试的副本。@ a。
如果您使用的是非本机对象,则可以使用这两种方法混合使用。通过指针引用旧实例变量的对象和singelton类的新实例变量,但这对int,string,float等不起作用......
编辑:正如Benoit指出的那样,在第二种方法中,“set”方法应该只是一个attr_accessor。实际上,您可以设置实例变量而无需定义新方法。通过item.instance_variable_set(:@, "cao")
答案 1 :(得分:1)
您正在尝试在Test
类上设置实例变量并在字符串实例中检索它们,这些不是相同的对象,并且不共享实例变量。您可以执行以下操作以在两个实例之间传递它:
class Test
def initialize(a)
@a = a
end
def item
item = "hola"
item.singleton_class.send :attr_accessor, :a
# set the item's @a with the Test instance one
item.a = @a
def item.singl
[self, @a].join(" + ")
end
item
end
end
test = Test.new("cao")
item = test.item
puts item.singl
答案 2 :(得分:1)
您没有尝试访问item
的实例变量。 item
是String
个对象,而@a
是Test
对象test
的实例变量。
两者都是独立的。从@a
访问item
的唯一方法是在test
中引用@a
(或item
),例如
class Test
attr_reader :a
def initialize(a)
@a = a
end
def item
item = "hola"
def item.singl
[self, @parent.a].join(" + ")
end
item.instance_variable_set(:@parent, self)
item
end
end
test = Test.new("cao")
item = test.item
item.singl