Как работает self при использовании его в методах инициализации и других методах класса? - PullRequest
1 голос
/ 12 февраля 2020

Я учусь ruby, и концепция self очень смущает меня в этом примере.

class Alpha
    def initialize
        self.A
    end

    def self.A
        puts "A"
    end 

    def self.B 
        self.A
        puts "B"
    end
end

, когда я пытался создать новый экземпляр из класса Alpha

Alpha.new

Я получил NoMethodError, но когда я вызвал B метод, он выполнялся нормально.

Alpha.B
# A
# B
#=>nil

Ответы [ 2 ]

1 голос
/ 12 февраля 2020

Сначала определите класс Alpha следующим образом.

class Alpha
  puts "self in Alpha = #{self}"

  def a
    puts "self in a = #{self}"
  end

  def Alpha.b
    puts "self in b = #{self}"
  end 

  def Alpha.c 
    puts "self in c = #{self}"
  end
end
  # self in Alpha = Alpha

У нас есть один метод экземпляра, Alpha#a и два метода класса, Alpha::b и Alpha::b. (Ссылка на методы экземпляра и класса в этом случае является соглашением Ruby, которое вы все время будете видеть в документах.)

Alpha.methods(false)
  #=> [:c, :b] 
Alpha.instance_methods(false)
  #=> [:a] 

См. Object :: method и Module # instance_methods , отмечая последствия включения аргумента false.

Методы экземпляра вызываются в экземплярах класса; Методы класса вызываются в классе.

alpha = Alpha.new
  #=> #<Alpha:0x000059c5ff614f08> 
alpha.a
  # self in a = #<Alpha:0x000059c5ff614f08>

Alpha.b
  # self in b = Alpha
Alpha.c
  # self in c = Alpha

Что если мы попытаемся вызвать метод экземпляра в классе или метод класса в instance?

Alpha.a
  #=> NoMethodError (undefined method `a' for Alpha:Class)
alpha.b
  #=> NoMethodError (undefined method `b' for #<Alpha:0x000059c5ff614f08>)

Обычно мы пишем класс следующим образом.

class Alpha
  def a
    puts "self in a = #{self}"
  end

  def self.b
    puts "self in b = #{self}"
  end 

  def self.c 
    puts "self in c = #{self}"
  end
end

В определении класса self равно Alpha, поэтому два способа написания класс эквивалентны. Единственная причина использования self состоит в том, что если мы решим позже изменить имя класса на Beta, нам не придется менять все Alpha на Beta в определениях методов класса.

Если мы хотим вызвать метод класса Alpha::b из метода экземпляра Alpha#a, мы должны изменить его следующим образом:

class Alpha
  def a
    puts "self in a = #{self}"
    self.class.b
  end
end

alpha.a
  # self in a = #<Alpha:0x000059c5ff614f08>
  # self in b = Alpha

Здесь self.class возвращает Alpha, и мы знаем, что возвращает Alpha.b.

Давайте изменим Alpha#a еще раз и добавим метод второго экземпляра:

class Alpha
  def a
    puts "self in a = #{self}"
    d
  end

  def d
    puts "self in d = #{self}"
  end
end

alpha.a
  # self in a = #<Alpha:0x000059c5ff614f08>
  # self in d = #<Alpha:0x000059c5ff614f08>

Я мог бы написать:

  def a
    puts "self in a = #{self}"
    self.d
  end

но self. не требуется и, как правило, не входит. Причина в том, что когда метод не имеет явного получателя, например, d in:

def a
  puts "self in a = #{self}"
  d
end

self становится получателем по умолчанию . Из вышеизложенного мы знаем, что в определении метода экземпляра self равно экземпляру alpha.

1 голос
/ 12 февраля 2020

initialize работает в контексте экземпляра, а не в контексте класса. Если вы хотите вызвать метод класса, вам нужно self.class.A. Или вы можете попробовать go e немного более сумасшедший и перезаписать класс new метод:

class Alpha
  def self.new
    self.A
    super # this actually calls initialize after object is created
  end

  [...]
end
...