单例方法的实例变量访问

fl0*_*00r 3 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
Run Code Online (Sandbox Code Playgroud)

die*_*mes 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 + "
Run Code Online (Sandbox Code Playgroud)

在你的例子中,你仍然有问题,在字符串的单例类中,@ 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
Run Code Online (Sandbox Code Playgroud)

设置实例字符串变量

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
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:正如Benoit指出的那样,在第二种方法中,"set"方法应该只是一个attr_accessor.实际上,您可以设置实例变量而无需定义新方法.通过item.instance_variable_set(:@, "cao")