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

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

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

class MyClass  
  @variable1 
end

и

class MyClass
  attr_accessor :variable1
end

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

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

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

29
задан 23.05.2017, 15:34

6 ответов

Переменная экземпляра не видна за пределами объекта, в котором она находится; но когда вы создаете 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

Надежда, которая проясняет ситуацию.

51
ответ дан 11.10.2019, 17:43
  • 1
    @ankit, там конкретное предложение, которое Вы находите сбивающими с толку? – Mike Samuel 11.10.2011, 20:49
  • 2
    на самом деле я происхождения Java, и в Java переменная экземпляра может быть сделана видимой к внешним модификаторам доступа использования (общественность, защищенная), вот почему я не смог понять, почему к переменным экземпляра в рубине нельзя получить доступ снаружи. Спасибо за объяснение, За Ваше здоровье!!! – Rajesh Pantula 17.10.2012, 13:09

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

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'
msg.@message
#==> 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

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

27
ответ дан 11.10.2019, 17:43
  • 1
    Проблема, я использую JSF, и я предполагаю точно так же, как другие платформы, это автоматически генерирует HTML.. Таким образом, я все еще невежествен о том, что Ваш записал.. Я также прошел шаблон закрытия.. Это таким образом плохо мне знакомо... – AngelsandDemons 11.10.2011, 21:27

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

8
ответ дан 11.10.2019, 17:43
  • 1
    Также для добавления:-Мой GUI не позволит пользователю вводить угловую скобку tags< >.It приведет к сбою клиентскую проверку и запрос won' t быть обработанным.. Как я понял, ПОЗВОЛЯЮ ли я ПОЛЬЗОВАТЕЛЮ вводить HTML-тэги в свой GUI тогда, я должен использовать шаблон закрытия для обеспечения, который все - допустимые теги и который все не допустимы... Исправьте меня, если является неправильным. – AngelsandDemons 11.10.2011, 21:31

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

1
ответ дан 11.10.2019, 17:43

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

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

ex: 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>'

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

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 , который объединяет как методы-установщики, так и методы-получатели, мы определяем его выше определений методов внутри класса. Методы attr_ * являются ярлыком для создания методов (setter и getter)

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
2
ответ дан 11.10.2019, 17:43
  • 1
    В отличие от этого, как в старомодном JSP/Servlet, JSF не имеет действительно понятия response.write(foo). Этот ответ немного сбивает с толку к пользователям, которые плохо знакомы с JSF 2.x. – BalusC 12.10.2011, 02:03

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

class MyClassA
  attr_accessor :x
end

был такой же, как

class MyClassB
  def x=(value) #java's typical setX(..)
    @x=value
  end
  def x
    @x
  end
end
0
ответ дан 11.10.2019, 17:43
  • 1
    Michelle' s решение работает на меня. На SDK менеджер переходят в: Отдельно оплачиваемые предметы > Intel x86 Emulator Accelerator (установщик HAXM). Тогда перейдите к своему SDK' s папка / Отдельно оплачиваемые предметы / Hardware_Accelerated_Execution_Manager и установка. – user1987392 01.05.2020, 15:27

Теги

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