Доступ к переменной экземпляра из одноэлементного метода - PullRequest
3 голосов
/ 28 октября 2011

Как я могу получить доступ к переменной экземпляра из одноэлементного метода?

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 ]

6 голосов
/ 28 октября 2011

Попробуйте использовать 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 и т. Д. *

РЕДАКТИРОВАТЬ: Как отметил Бенуа, во втором методе метод "set" должен быть просто attr_accessor. Фактически, вы можете установить переменную экземпляра, не определяя новый метод вообще. Через item.instance_variable_set(:@, "cao")

1 голос
/ 28 октября 2011

Вы не пытаетесь получить доступ к переменной экземпляра 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
1 голос
/ 28 октября 2011

Вы пытаетесь установить переменную вашего экземпляра для класса 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...