Проблема в понимании разницы между использованием self и @ в инициализации (конструкторе) класса Ruby - PullRequest
0 голосов
/ 06 июня 2018

Я пробираюсь сквозь книгу «Хорошо обоснованный рубин» и надеялся получить некоторые пояснения относительно своего понимания себя и @ для инициализации.

Есть момент, когда вы создаете простой класс Ticket, используя "self".установить место и дату.В общих чертах я понимаю это «я».устанавливает место и дату для текущего экземпляра Ticket, в то время как @ устанавливает переменную экземпляра ... но я не слишком уверен, почему бы вместо этого не использовать переменную экземпляра?

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

class Ticket
  attr_accessor :venue, :date
  def initialize(venue, date)
    self.venue = venue
    self.date = date
  end
end

Любая помощь, чтобы прояснить мое понимание будет высоко ценится!

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

То же самое, но один рассматривается как переменная (@), а другой как метод (благодаря getter и setter). Пример 4 «раскрывает трюк».

Я надеюсь, что следующие примеры могут быть понятны:


Пример 1

class Ticket

  attr_accessor :venue

  def initialize(venue)
    self.venue = venue
  end

  def are_the_same?
    p self.venue == @venue
    p self.venue === @venue
    p self.venue.eql? @venue
    p self.venue.equal? @venue
  end

end

ticket = Ticket.new('Broadway') # this is an instance of Ticket

ticket.are_the_same?

#=> true
#=> true
#=> true
#=> true

См. Этот великий пост для равных .


Пример 2

class Ticket

  @@double_arroba = 'class variable' # class variable
  attr_accessor :venue

  def initialize(venue)
    self.venue = venue
  end

  def whats_self?
    p self # instance itself
  end

  def venue_self
    p self.venue # instance itself  calling its variable
  end

  def venue_arroba
    p @venue # instance variable directly
  end

  def whats_double_arroba # instance method using a class variable
    p @@double_arroba
  end

  def self.whats_double_arroba # class method using a class variable
    p @@double_arroba
  end

  def self.whats_self? # class method calling itself
    p self
  end

end

ticket = Ticket.new('Broadway') # this is an instance of Ticket

p ticket #=> #<Ticket:0x007fb3fb0f1868 @venue="Broadway">
ticket.whats_self? #<Ticket:0x007fb3fb0f1868 @venue="Broadway">
p ticket.venue #=> "Broadway" #thanks to attr_accessor
ticket.venue_self #=> "Broadway"
ticket.venue_arroba #=> "Broadway"

ticket.whats_double_arroba #=> "class variable"
Ticket.whats_double_arroba #=> "class variable"
Ticket.whats_self? #=> Ticket

Пример 3

Что произойдет, еслиудалить attr_accessor?

class Ticket

  # attr_accessor :venue #comment out attr_accessor

  def initialize(venue)
    # self.venue = venue # venue method is not defined
    @venue = venue # so you need to use @
  end

  def venue_self
    # p self.venue # not working, self method is not available is nota available
  end

  def venue_arroba
    p @venue # instance variable directly
  end

end

ticket = Ticket.new('Broadway') # this is an instance of Ticket

p ticket #=> #<Ticket:0x007fb3fb0f1868 @venue="Broadway">
# p ticket.venue # does not work, no access
ticket.venue_self #=> nil, because commented the method code
ticket.venue_arroba #=> "Broadway"
# ticket.whats_double_arroba # not working

Пример 4

Хитрость: геттер и сеттер

# class with getter and setter

class Ticket

  def venue=(value) # setter (attr_reader)
    @venue = value
  end

  def venue # getter (attr_writer)
    @venue
  end

  def self_venue
    self.venue # (*) you can omit self and write just venue
  end

end

ticket = Ticket.new # ticket is the instance
ticket.venue="Brodway" # setter method .venue= in action
p ticket.venue #=> "Brodway" # getter method .venue in action
p ticket.self_venue #=> "Brodway" # calls the method .self_venue on the instance, which calls the getter method .venue (*)


# or write simply this code below, to let ruby build itself getter and setter

class Ticket

  attr_accessor :venue

end
0 голосов
/ 06 июня 2018

Когда вы используете attr_accessor :venue, вы по сути делаете это.

def venue
  @venue
end 

def venue=(value)
  @venue = value
end 

Когда вы делаете attr_writer :venue, вы делаете

def venue=(val)
  @venue = val 
end 

Когда вы делаете attr_reader :venue, вы делаете

def venue
  @venue 
end

Обратите внимание, что @instance_variable по умолчанию nil или если он неинициализирован.Чтобы увидеть это в действии, введите irb в своем терминале и нажмите ввод.Затем введите один @ и спамите кучу символов после него.@ausdhyf934234092348 будет ноль.

Когда вы находитесь внутри Ticket#initialize, вы действуете как экземпляр объекта, поэтому self вернет текущий экземпляр.self.class вернет класс и предоставит вам доступ к любым методам уровня класса.

class Ticket
  VENUE_SIZES = [:small, :large]

  def self.venue_sizes
    VENUE_SIZES
  end 

  def initialize(venue, date)
    # ... 
    self.venue_sizes # NoMethodError
    self.class.venue_sizes # [:small, :large]
  end 

end

Поднимаясь по цепочке, если вы действуете как класс, а не как экземпляр класса, вызываяself.class - или self.class.class, если вы действуете как экземпляр, вернет Class

attr_accessor - просто синтаксический сахар;это было сделано из-за рутинной рутины того, что нужно снова и снова писать эти методы получения / установки.Есть более сложные проблемы, такие как написание нашего nadnerb_accessor на Ruby (хотя attr_accessor реализован на C):

class Ticket
  def self.nadnerb_accessor(*names)
    names.each do |name|
      define_method(name) do
        instance_variable_get(:"@#{name}")
      end
      define_method("#{name}=") do |value|
        instance_variable_set(:"@#{name}", value)
      end
    end
  end

  nadnerb_accessor :venue, :price

  def initialize(venue, price)
    self.venue = venue
    self.price = price
  end

  def inspect
    "#<Ticket @venue=\"#{@venue}\" @price=\"#{@price}\">"
  end
end

ticket = Ticket.new("StackOverflow", "$5")
puts ticket.inspect 

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...