Переменная класса Ruby, используемая как переменная экземпляра класса [duplicate]

Ссылка NullReferenceException или Object, не установленная на экземпляр объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:

Предположим, что у вас есть класс с именем Student.

public class Student
{
    private string FirstName;
    private string LastName;
    public string GetFullName()
    {
        return FirstName + LastName;
    }
}

Теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя учащегося.

public class StudentInfo
{      
    public string GetStudentName()
    {
        Student s;
        string fullname = s.GetFullName();
        return fullname;
    }        
}

Как видно из вышеприведенного кода, оператор Student s - объявляет только переменную типа Student, обратите внимание, что класс Student не создается в этой точке. Следовательно, когда выполняется выполнение инструкции s.GetFullName (), она выкинет исключение NullReferenceException.

13
задан Andrew Grimm 28 September 2011 в 01:08
поделиться

4 ответа

Пройдем через код, будем ли мы?

#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 не имеет метода #+ , это приведет к возникновению исключения 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 является методом экземпляра, заключается в том, что инициализация объекта, очевидно, выполняется для каждого объекта. Для удобства существует стандартный метод фабричного класса, называемый 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.

37
ответ дан Jörg W Mittag 4 September 2018 в 07:01
поделиться

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

def initialize
  @game_score = 0
end

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

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

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

16
ответ дан DigitalRoss 4 September 2018 в 07:01
поделиться

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

class << Bowling
  attr_accessor :game_score
end

Bowling.game_score #=> 0

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

9
ответ дан khelll 4 September 2018 в 07:01
поделиться

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

def initialize @game_score = 0 end

0
ответ дан user 4 September 2018 в 07:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: