Подтвердить что ты не робот

Всего новичков: переменные экземпляра в рубине?

Измените общий вопрос newbiew, но почему @game_score всегда nil?

#bowling.rb

class Bowling
  @game_score = 0
    def hit(pins)
        @game_score = @game_score + pins
    end

    def score
        @game_score
    end
end
4b9b3361

Ответ 1

Пропустить через код, будем ли мы?

#bowling.rb

class Bowling
  @game_score = 0 # (1)

В этот момент (1) мы все еще находимся внутри класса Bowling. Помните: классы - это просто объекты, подобные любым другим. Итак, в этот момент вы присваиваете 0 переменной экземпляра @game_score объекта класса Bowling.

 def hit(pins)
  @game_score = @game_score + pins # (2)

Теперь (2) мы находимся внутри метода экземпляра класса Bowling. I.e: Это метод, который будет принадлежать экземпляру Bowling. Итак, теперь переменная экземпляра @game_score принадлежит экземпляру класса Bowling, а не самому классу.

Поскольку эта переменная экземпляра никогда не инициализируется ничем, она будет оцениваться как nil (в Ruby неинициализированные переменные всегда оцениваются до nil), поэтому это оценивается как @game_score = nil + pins, а поскольку nil не имеет a #+, это приведет к возникновению исключения NoMethodError.

 end
 def score
  @game_score # (3)

И здесь (3) мы снова находимся внутри метода экземпляра класса Bowling. Это всегда будет оцениваться как nil по причине, описанной выше: @game_score никогда не инициализируется, поэтому он оценивает nil.

 end
end

Мы можем использовать возможности отражения Ruby, чтобы посмотреть, что происходит:

p Bowling.instance_variable_get(:@game_score) # => 0
b = Bowling.new
p b.instance_variable_get(:@game_score) # => nil

Теперь добавьте значение в переменную экземпляра:

b.instance_variable_set(:@game_score, 1)
p b.score # => 1
b.hit(3)
p b.score # => 4

Итак, мы видим, что все работает так, как должно, нам нужно только выяснить, как убедиться, что переменная экземпляра инициализируется.

Для этого нам нужно написать метод инициализации. Как ни странно, метод инициализации фактически является методом частного экземпляра, который называется initialize. (Причина, почему initialize - это метод экземпляра, а не метод класса, на самом деле довольно прост. Ruby разбивает создание объекта в два этапа: выделение памяти и инициализация объекта. Распределение памяти выполняется методом класса alloc и объектом инициализация выполняется методом экземпляра с именем initialize. (Objective-C программисты это узнают.) Причина, по которой alloc - это метод класса, просто состоит в том, что на данный момент выполнения пока нет экземпляра. что initialize является методом экземпляра, заключается в том, что инициализация объекта, очевидно, выполняется для каждого объекта. Для удобства существует стандартный метод класса factory, называемый new, который вызывает для вас как alloc, так и initialize.)

class Bowling
 def initialize
  @game_score = 0
 end
end

Позвольте проверить это:

c = Bowling.new
p c.score # => 0
c.hit(2)
p c.score # => 2

BTW: только некоторые незначительные подсказки в стиле Ruby: отступы - это 2 пробела, а не 1 вкладка. И ваш метод hit более идиоматически будет @game_score += pins.

Ответ 2

Поскольку у вас нет

def initialize
  @game_score = 0
end

Назначение в определении класса не делает то, что, по вашему мнению, делает, и когда hit вызывается, он не может добавить к nil.

Если вы теперь спросите, что случилось с @game_score?, ну, всегда помните, что Class является объектом, а Object - классом.

Так здорово, как классы Ruby имеют такое "реальное" существование в Zen. Ruby точно не имеет названных классов, скорее, имена классов являются ссылками на объекты класса Class. Назначая @game_score вне метода экземпляра, вы создали переменную экземпляра класса, атрибут объекта класса Bowling, который является экземпляром класса Class. Эти объекты, в общем, не очень полезны. (См. Главу 1 "Путь Руби", Хэл Фултон.)

Ответ 3

@game_score, определенная называется переменной класса экземпляра, которая является переменной, определенной для объекта singleton class:

class << Bowling
  attr_accessor :game_score
end

Bowling.game_score #=> 0

Это, как вы можете отличить от обычных переменных экземпляра, определенных для объектов экземпляра.

Ответ 4

@game_score никогда не получит здесь значение нуля - вам нужно его инициализировать внутри, как в

def инициализировать @game_score = 0 конец