Ruby 从singleton方法访问实例变量

Ruby 从singleton方法访问实例变量,ruby,singleton,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 您试

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

您试图在
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

尝试使用define_方法。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的singleton类中,还没有定义。这主要是因为在此上下文中self是字符串实例,而不是存在
@a
的测试实例。要解决此问题,可以将实例变量重新绑定到其他对象,但这可能不是您要寻找的行为。您还可以在新的singleton类中设置实例变量

比如说,

重新绑定变量 设置一个实例字符串变量 注意这两种方法之间的差异很重要。在第一种方法中,我们通过原始对象保留对原始实例变量的引用。在第二个方法中,我们创建一个新的实例变量,绑定在新的singleton类下,包含原始测试的副本。@a

如果您使用的是非本机对象,则可以同时使用这两种方法。通过指针使用singelton类新实例变量引用旧实例变量的对象,但这对int、string、float等不起作用


编辑:正如Benoit指出的,在第二种方法中,“set”方法应该只是一个attr_访问器。事实上,您可以设置实例变量,而无需定义新方法。通过
item.instance\u variable\u set(:@,“cao”)
您没有试图访问
item
的实例变量
item
是一个
String
对象,而
@a
Test
对象
Test
的一个实例变量

两者都是独立的。从
项目
访问
@a
的唯一方法是在
项目
中引用
测试
(或
@a
),例如

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

我很难理解上一个示例,您在item类中硬编码“cao”字符串,而不是获取传递给测试初始值设定项的内容。你想把它定义为属性设置器吗?我太懒了。我做出这种区分是为了说明第二种方法中的两个@a并不相同。我假设op可以推断这个方法“应该”是一个属性设置器。我会澄清的。谢谢在您的示例中,您有一个小问题。新项引用了@a的副本,而不是@a本身。这是一个问题,如果测试。a不断变化。例如,这将导致不正确的结果。项目1.1;test.a=“hi”;项目1.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
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