单例方法的实例变量访问

时间:2011-10-28 08:06:22

标签: ruby singleton

如何从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

3 个答案:

答案 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的实例变量。 itemString个对象,而@aTest对象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