Странное поведение ruby ​​attr_accessor

У меня есть этот блок кода:

class CallMe
  attr_accessor :a, :b, :c

  def self.start(*args)
     self.new(*args).get_answer
  end

  def initialize(a,b,c)
    @a = a
    @b = b
    @c = c
  end

  def get_answer 
    if c
      b = nil
    else
      return b 
    end
   end
end
answer = CallMe.start(1,2,nil)

Почему, когда я запускаю его в IRB, я всегда получаю answer = nil четный логический случай - получить значение b, равное 2

2 ответа

Решение

Переменный эффект Подъем используется во многих языках. Для Ruby это описано в официальной документации:

Локальная переменная создается, когда синтаксический анализатор встречает назначение, а не когда происходит назначение

Так, get_answer метод создает локальную переменную b независимо от стоимости c, И назначает локальную переменную b в nil при создании. затем get_answer возвращает локальную переменную b который всегда nil,

Правильный метод:

def get_answer
  c ? self.b = nil : b
end

Это потому, что в контексте if заявление, которое вы на самом деле переопределить b когда вы печатаете b = nil, Для Ruby не ясно, хотите ли вы вызвать метод объекта :b или создать новую переменную b, В таких случаях приоритет всегда переходит от глобального к ближайшему контексту, в данном случае - к контексту внутри if блок.

Если вы измените

if c
  b = nil
else
  return b
end

# to 
if c
  # b = nil
  # or
  self.b = nil
else
  return b

Вы заметите, что это работает, как вы ожидали.

Другие вопросы по тегам