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

Разница между @instance_variable и attr_accessor

Я только начал изучать ruby, и я не вижу разницы между @instace_variable и объявленным атрибутом с помощью attr_accessor.

В чем разница между следующими двумя классами:

class MyClass  
  @variable1 
end

и

class MyClass
  attr_accessor :variable1
end

Я искал много учебников онлайн, и все используют разные обозначения, нужно ли что-либо делать с рубиновой версией? Я также искал несколько старых потоков в StackOverflow

Что такое attr_accessor в Ruby?
В чем разница между этими двумя определениями инициализации класса Ruby?

Но все же я не могу понять, что является лучшим способом использования.

4b9b3361

Ответ 1

Переменная экземпляра не видна вне объекта, в котором он находится; но когда вы создаете attr_accessor, он создает переменную экземпляра, а также делает ее видимой (и редактируемой) вне объекта.

Пример с переменной экземпляра (не attr_accessor)

class MyClass
  def initialize
    @greeting = "hello"
  end
end

m = MyClass.new
m.greeting #results in the following error:
  #NoMethodError: undefined method `greeting' for #<MyClass:0x007f9e5109c058 @greeting="hello">

Пример с помощью attr_accessor:

class MyClass
  attr_accessor :greeting

  def initialize
    @greeting = "hello"
  end
end

m2 = MyClass.new
m2.greeting = "bonjour" # <-- set the @greeting variable from outside the object
m2.greeting #=> "bonjour"   <-- didn't blow up as attr_accessor makes the variable accessible from outside the object

Надеюсь, что это ясно.

Ответ 2

Переменные экземпляра не видны вне класса.

class MyClass
  def initialize
    @message = "Hello"
  end
end

msg = MyClass.new
@message
#==> nil   # This @message belongs to the global object, not msg
msg.message
#==> NoMethodError: undefined method `message'
[email protected]
#==> SyntaxError: syntax error, unexpected tIVAR

Теперь вы всегда можете сделать это:

msg.instance_eval { @message }

Но это неудобно и обмануто. Похищение кого-то другого может быть образовательным, но ваш клиентский код не должен делать это, если вы хотите получить надежные результаты. С другой стороны, если вы хотите, чтобы клиенты могли видеть эти значения, не используйте их instance_eval; вместо этого определите метод, который выполняет трюк:

class MyClass
  def message 
    return @message
  end
end
msg.message
# ==> "Hello"

Поскольку вы так часто хотите это сделать, Ruby предоставляет ярлык, чтобы упростить его. Код ниже имеет тот же результат, что и код выше:

class MyClass
  attr_reader :message
end

Это не новый тип переменной; это просто сокращенный способ определения метода. Вы можете посмотреть msg.methods и увидеть, что теперь он имеет метод message.

Теперь, если вы хотите, чтобы посторонние могли видеть не только значение переменной экземпляра, но и изменить его? Для этого вам нужно определить другой метод назначения, с = в имени:

class MyClass
  def message=(new_value)
    @message = new_value
  end
end
msg.message = "Good-bye"
msg.message
# ==> "Good-bye"

Обратите внимание, что операторы присваивания здесь полумагические; даже если есть пробел между msg.message и =, Ruby все еще знает, чтобы вызвать метод message=. Комбинированные операторы типа += и т.д. Также вызовут вызов метода.

Опять же, это общий дизайн, поэтому Ruby также предлагает ярлык для него:

class MyClass
  attr_writer :message
end

Теперь, если вы используете attr_writer самостоятельно, вы получаете атрибут, который можно изменить, но не увидеть. Есть несколько нечетных вариантов использования, когда то, что вы хотите, но большую часть времени, если вы хотите, чтобы посторонние изменяли переменную, вы хотите, чтобы они тоже могли ее прочитать. Вместо того, чтобы объявлять как attr_reader, так и attr_writer, вы можете объявить оба сразу:

class MyClass
  attr_accessor :message
end

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

Ответ 3

attr_accesor дает вам методы для чтения и записи переменных экземпляра. Переменные экземпляра запрещены для скрытия от внешнего мира, поэтому для общения с ними у нас должны быть attr _ibute методы accesor.

Ответ 4

В OOPS у нас есть концепция, называемая инкапсуляция, которая означает, что внутреннее представление объекта обычно скрыто от просмотра вне определения объекта. Только сам объект может возиться со своим внутренним состоянием. Внешний мир не может.

Каждый объект обычно определяется его состоянием и поведением, в ruby переменные экземпляра называются внутренним состоянием или состоянием объекта, и в соответствии с OOPS состояние не должно быть доступно любому другому объекту, поэтому мы придерживаемся Encapsulation.

class Foo def initialize(bar) @bar = bar end end: class Foo def initialize(bar) @bar = bar end end

Выше мы определили класс Foo и в методе initialize мы инициализировали переменную экземпляра (атрибут) или (свойство). когда мы создаем новый объект ruby, используя новый метод, который, в свою очередь, вызывает метод инициализации внутри, когда метод запущен, переменная экземпляра @bar объявляется и инициализируется, и она будет сохранена как состояние объекта.

Каждая переменная экземпляра имеет свое собственное внутреннее состояние и уникальна для самого объекта, каждый метод, который мы определяем в классе, будет изменять внутреннее состояние объекта в соответствии с определением и целью метода. здесь метод initialize делает то же самое, например, создает новую переменную экземпляра.

var object = Foo.new(1)
#<Foo:0x00000001910cc0 @bar=1>

В фоновом режиме ruby создал переменную экземпляра (@bar = 1) и сохранил значение как состояние объекта внутри объекта "объект". мы можем проверить это с помощью метода instance_variables, и эти методы возвращают массив, содержащий все переменные экземпляра объекта в соответствии с текущим состоянием объекта.

object.instance_variables
#[
     [0]: @bar
 ]

мы можем видеть переменную экземпляра '@bar' выше. который создается, когда мы вызываем метод initialize объекта. эта переменная @bar не должна быть видимой (скрытой) по умолчанию, и поэтому ее не могут видеть другие снаружи объекта, кроме объекта, изнутри. Но объект может возиться со своим собственным внутренним состоянием, и это означает, что он может показать или изменить значения, если мы дадим ему способ сделать это, эти два можно сделать, создав новые методы экземпляра в классе.

когда мы хотим увидеть переменную @bar, вызвав ее, мы получаем ошибку, так как по умолчанию мы не можем видеть состояние объекта.

show = object.bar
#NoMethodError: undefined method 'bar' for #<Foo:0x00000001910cc0 @bar=1>
#from (irb):24
#from /home/.rvm/rubies/ruby-2.0.0-p648/bin/irb:12:in '<main>'

Но мы можем получить доступ к переменным двумя способами, эти два называются сеттер и геттер методы, позволяющие объект, чтобы показать или изменить свое внутреннее состояние (переменные экземпляра/атрибуты/свойства) соответственно.

class Foo
  def bar
    @bar
  end

  def bar=(new_bar)
    @bar = new_bar
  end
end

Мы определили методы getter (bar) и setter (bar =), мы можем назвать их любым способом, но переменная экземпляра внутри должна совпадать с переменной экземпляра, которой мы хотим показать или изменить значение. сеттеры и геттеры являются в некотором смысле нарушением концепций OOPS, но они также являются очень мощными методами.

когда мы определяем эти два метода, повторно открывая класс и определяя их, когда мы вызываем объект с помощью методов, мы можем просматривать переменные экземпляра (здесь @foo) и также изменять его значение.

object.bar
1

object.bar=2
2

object.bar
2

Здесь мы вызвали метод bar (getter), который возвращает значение @bar, а затем мы вызвали bar = метод (setter), который мы указали в качестве аргумента new_value, и он изменил значение переменной экземпляра (@bar), и мы можем посмотрите снова, вызвав метод bar.

В ruby у нас есть метод attr_accessor, который объединяет методы как setter, так и getter, мы определяем его выше определений методов внутри класса. Методы attr_ * - это ярлык для создания методов (сеттер и геттер)

class Foo
  attr_accessor :bar
end

мы должны предоставить символ (: bar) в качестве аргумента методу attr_accessor, который создает методы как setter, так и getter внутри, с именами методов в качестве предоставленного имени символа.

Если нам нужен только метод получения, мы можем вызвать attr_reader: bar. Если нам нужен только метод установки, мы можем вызвать attr_writer: bar.

attr_accessor создает методы как attr_writer, так и attr_reader

мы можем предоставить столько переменных экземпляра, сколько мы хотим, методам attr_ *, разделенным запятыми

class Foo
  attr_writer :bar
  attr_reader :bar
  attr_accessor :bar, :baz
end

Ответ 5

Поскольку attr_accessor определяет методы, вы можете вызывать их извне класса. A @variable доступен только изнутри класса.

Ответ 6

И еще один ответ, более компактный (для разработчиков Java) attr_accessor :x создает attr_accessor :x получения и установки для @x

class MyClassA
  attr_accessor :x
end

такой же как

class MyClassB
  def x=(value) #java typical setX(..)
    @x=value
  end
  def x
    @x
  end
end