Что такое attr accessor в Ruby?

Мне трудно понять attr_accessor в Ruby. Кто-нибудь может мне это объяснить?

18 ответов


Допустим у вас есть класс Person.

class Person
end

person = Person.new
person.name # => no method error

очевидно, мы никогда не определяется методом name. Давайте сделаем это.

class Person
  def name
    @name # simply returning an instance variable @name
  end
end

person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error

Ага, мы можем прочитать имя, но это не значит, что мы можем назначить имя. Это два разных метода. Первая называется читатель и последний называется писатель. Мы еще не создали писателя, так что давайте сделаем это.

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

потрясающе. Теперь мы можем писать и читать переменные экземпляра @name использование методов чтения и записи. Кроме того, это делается так часто, зачем тратить время на написание этих методов каждый раз? Мы можем сделать это проще.

class Person
  attr_reader :name
  attr_writer :name
end

даже это может повторяться. Когда вы хотите, чтобы и читатель и писатель просто использовать accessor!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

работает так же! И угадайте, что: переменная экземпляра @name в нашем лице объект будет установлен так же, как когда мы сделали это вручную, поэтому вы можете использовать его в других методах.

class Person
  attr_accessor :name

  def greeting
    "Hello #{@name}"
  end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

вот он. Чтобы понять, как attr_reader, attr_writer и attr_accessor методы фактически генерируют методы для вас, читают другие ответы, книги, ruby docs.


attr_accessor is метод. (Ссылка должна дать больше информации о том, как она работает - посмотрите на созданные пары методов, и учебник должен показать вам, как ее использовать.)

фишка в том, что class is не определение в Ruby (это "просто определение" на таких языках, как C++ и Java), но это выражения. Именно во время этой оценки, когда attr_accessor метод вызывается что, в свою очередь, изменяет текущий класс-помните неявный приемник:self.attr_accessor, где self является" открытым " объектом класса на данный момент.

необходимость attr_accessor и друзьям, это, так:

  1. Ruby, как и Smalltalk, не позволяет обращаться к переменным экземпляра вне методов1 для этого объекта. То есть переменные экземпляра не могут быть доступны в x.y форма, как обычно, скажем, Java или даже Python. В Руби y is всегда берется как сообщение для отправки (или"метод вызова"). Таким образом attr_* методы создают обертки, которые прокси экземпляр @variable доступ через динамически созданные методы.

  2. шаблонный отстой

надеюсь, это прояснит некоторые из маленьких деталей. Удачи в кодировании.


1 это не совсем так, и есть некоторые "техники" по этой, но нет поддержки синтаксиса доступ к переменной" public instance".


attr_accessor (как указано в @pst) просто метод. Что он делает, так это создает больше методов для вас.

так этот код:

class Foo
  attr_accessor :bar
end

эквивалентно этому коду:

class Foo
  def bar
    @bar
  end
  def bar=( new_value )
    @bar = new_value
  end
end

вы можете написать такой метод самостоятельно в Ruby:

class Module
  def var( method_name )
    inst_variable_name = "@#{method_name}".to_sym
    define_method method_name do
      instance_variable_get inst_variable_name
    end
    define_method "#{method_name}=" do |new_value|
      instance_variable_set inst_variable_name, new_value
    end
  end
end

class Foo
  var :bar
end

f = Foo.new
p f.bar     #=> nil
f.bar = 42
p f.bar     #=> 42

attr_accessor очень просто:

attr_accessor :foo

ярлык для:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

это не более чем геттер/сеттер для объекта


в основном они подделывают общедоступные атрибуты данных, которых у Ruby нет.


Это просто метод, который определяет методы getter и setter для переменных экземпляра. Примером реализации может быть:

def self.attr_accessor(*names)
  names.each do |name|
    define_method(name) {instance_variable_get("@#{name}")} # This is the getter
    define_method("#{name}=") {|arg| instance_variable_set("@#{name}", arg)} # This is the setter
  end
end

Я также столкнулся с этой проблемой и написал несколько пространный ответ на этот вопрос. Есть некоторые отличные ответы на это уже, но кто ищет больше разъяснений, я надеюсь, что мой ответ может помочь

Initialize Метод

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

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


  def greeting
    "Hello #{@name}"
  end
end

person = Person.new("Denis")
puts person.greeting

In в приведенном выше коде мы устанавливаем имя "Denis" с помощью метода initialize, передавая Dennis через параметр Initialize. Если бы мы хотели установить имя без метода initialize, мы могли бы сделать так:

class Person
  attr_accessor :name

  # def initialize(name)
  #     @name = name
  # end

  def greeting
    "Hello #{name}"
  end
end

person = Person.new
person.name = "Dennis"
puts person.greeting

в приведенном выше коде мы устанавливаем имя, вызывая метод attr_accessor setter с помощью person.имя, а не установка значений при инициализации объекта.

оба "метода" выполнения этой работы, но initialize экономит наше время и строки программного кода.

это единственное задание инициализации. Вы не можете вызвать initialize как метод. Чтобы фактически получить значения объекта экземпляра, вам нужно использовать геттеры и сеттеры (attr_reader (get), attr_writer(set) и attr_accessor(оба)). Подробнее об этом см. ниже.

геттеры, сеттеры (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: вся цель геттера-вернуть значение конкретного экземпляра переменная. Посетите пример кода ниже для разбивки по этому.

class Item

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

  def item_name
    @item_name
  end

  def quantity
     @quantity
  end
end

example = Item.new("TV",2)
puts example.item_name
puts example.quantity

в приведенном выше коде вы вызываете методы "item_name" и "quantity"на экземпляре элемента "example". Тот " ставит пример.item_name" и "пример.quantity "вернет (или" получит") значение параметров, которые были переданы в" пример", и отобразит их на экране.

к счастью, в Ruby есть свойственный метод, который позволяет нам писать этот код более кратко; способ attr_reader. См. код ниже;

class Item

attr_reader :item_name, :quantity

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

end

item = Item.new("TV",2)
puts item.item_name
puts item.quantity

этот синтаксис работает точно так же, только он спасает нас шесть строк кода. Представьте, если бы у вас было еще 5 состояний, относящихся к классу элементов? Код быстро станет длинным.

Setters, attr_writer: то, что пересекло меня сначала с методами setter, заключается в том, что в моих глазах он, казалось, выполнял идентичную функцию с методом initialize. Ниже я объясняю разницу, основанную на моем понимании;

As как указано выше, метод initialize позволяет задавать значения для экземпляра объекта при создании объекта.

но что, если вы хотите установить значения позже, после создания экземпляра, или изменить их после их инициализации? Это будет сценарий, в котором вы будете использовать метод setter. ВОТ В ЧЕМ РАЗНИЦА. Вам не нужно "устанавливать" определенное состояние, когда вы используете метод attr_writer изначально.

ниже код является примером использование метода setter для объявления значения item_name для этого экземпляра класса Item. Обратите внимание, что мы продолжаем использовать метод getter attr_reader, чтобы получить значения и распечатать их на экране, на случай, если вы хотите протестировать код самостоятельно.

class Item

attr_reader :item_name

  def item_name=(str)
    @item_name = (str)
  end

end

приведенный ниже код является примером использования attr_writer, чтобы еще раз сократить наш код и сэкономить нам время.

class Item

attr_reader :item_name
attr_writer :item_name

end

item = Item.new
puts item.item_name = "TV"

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

class Item

attr_reader :item_name

  def initialize(item_name)
    @item_name = item_name
  end

end

item = Item.new("TV")
puts item.item_name

attr_accessor: выполняет функции как attr_reader, так и attr_writer, сохраняя еще одну строку кода.


Я думаю, что часть того, что смущает новых рубистов / программистов (как и я):

"Почему я не могу просто сказать экземпляру, что у него есть какой-либо атрибут (например, имя), и дать этому атрибуту значение одним махом?"

немного более обобщенный, но вот как он щелкнул для меня:

дано:

class Person
end

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

так если мы тут:

baby = Person.new

...и постарайся дать им имя...

baby.name = "Ruth"

получаем потому что в Rubyland класс объекта Person не является чем-то, что связано или способно иметь "имя" ... пока!

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

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


если вы знакомы с концепцией ООП, вы должны ознакомиться с методом геттера и сеттера. attr_accessor делает то же самое в Ruby.

геттер и сеттер в общем порядке

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"

Сеттера

def name=(val)
  @name = val
end

Геттер

def name
  @name
end

метод геттера и сеттера в Ruby

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"

большинство приведенных выше ответов используют код. Это объяснение пытается ответить на него без использования какого-либо кода:

объяснение по аналогии

внешние стороны не могут получить доступ к внутренним секретам ЦРУ

  • давайте представим себе действительно секретное место: ЦРУ. Никто не знает, что происходит в ЦРУ, кроме людей внутри ЦРУ. Другими словами, внешние люди не могут получить доступ к какой-либо информации в ЦРУ. Но ведь нехорошо иметь организацию, которая полностью секретна, определенная информация предоставляется внешнему миру - только то, о чем ЦРУ хочет, чтобы все знали: например, директор ЦРУ, насколько экологически чистый этот отдел по сравнению со всеми другими правительственными ведомствами и т. д. Другая информация: например, кто является его тайными агентами в Ираке или Афганистане - эти типы вещей, вероятно, останутся секретом для следующих 150 годы.

  • Если вы находитесь вне ЦРУ, вы можете получить доступ только к информации, которую он сделал доступной для общественности. Или, используя жаргон ЦРУ, вы можете получить доступ только к информации, которая "очищена".

  • информация, которую ЦРУ хочет предоставить широкой общественности за пределами ЦРУ, называется:атрибуты.

значение чтения и записи атрибуты:

  • в случае ЦРУ большинство атрибутов "только для чтения". Это означает, если вы являетесь стороной внешний в ЦРУ, вы можете спрашиваю:не может делать с атрибутами "только для чтения" - это вносить изменения в изменения в ЦРУ. например, вы не можете сделать телефонный звонок и вдруг решить что вы хотите, чтобы Ким Кардашьян была Директор, или что вы хотите, чтобы Пэрис Хилтон была главнокомандующим.

  • Если атрибуты дали вам доступ "write", то вы можете внести изменения, если хотите, даже если вы были снаружи. В противном случае, единственное, что вы можете сделать, это прочитать.

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

объекты внутри класса могут легко получить доступ друг к другу

  • С другой стороны, если вы были уже внутриза пределами ЦРУ, вам просто не будет предоставлен доступ: вы не сможете узнать, кто они (читать access), и вы не сможете изменить свою миссию (write access).

то же самое с классами и вашей способностью получать доступ к переменным, свойствам и методам в них. НТН! Любые вопросы, пожалуйста, задайте, и я надеюсь, что смогу уточнить.


проще говоря, он определит сеттера и геттера для класса.

отметим, что

attr_reader :v is equivalant to 
def v
  @v
end

attr_writer :v is equivalant to
def v=(value)
  @v=value
end

Так

attr_accessor :v which means 
attr_reader :v; attr_writer :v 

эквивалентны для определения сеттера и геттера для класса.


просто attr-accessor создает getter и setter методы для указанных атрибутов


другой способ понять это-выяснить, какой код ошибки он устраняет, имея attr_accessor.

пример:

class BankAccount    
  def initialize( account_owner )
    @owner = account_owner
    @balance = 0
  end

  def deposit( amount )
    @balance = @balance + amount
  end

  def withdraw( amount )
    @balance = @balance - amount
  end
end

доступны следующие методы:

$ bankie = BankAccout.new("Iggy")
$ bankie 
$ bankie.deposit(100)
$ bankie.withdraw(5)

следующие методы выдает ошибку:

$ bankie.owner     #undefined method `owner'... 
$ bankie.balance   #undefined method `balance'...

owner и balance не, технически, метод, но атрибутом. Класс BankAccount не имеет def owner и def balance. Если это так, то вы можете использовать две команды ниже. Но этих двух методов не существует. Тем не менее, вы можете открыть атрибуты, как если бы вы открыть способ через attr_accessor!! отсюда слово attr_accessor. Атрибут. Средство доступа. Он обращается к атрибутам, как вы бы получить доступ к методу.

добавлять attr_accessor :balance, :owner позволяет читать и писать balance и owner "метод". Теперь вы можете использовать последние 2 метода.

$ bankie.balance
$ bankie.owner

определяет именованный атрибут для этого модуля, где имя является символом.id2name, создание переменной экземпляра (@name) и соответствующий метод доступа для ее чтения. Также создает метод name= для установки атрибута.

module Mod
  attr_accessor(:one, :two)
end
Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]

чтобы суммировать атрибут accessor aka attr_accessor дает вам два бесплатных метода.

Как в Java они называют геттерами и сеттерами.

многие ответы показали хорошие примеры, поэтому я просто буду краток.

#the_attribute

и

#the_attribute=

в старых документах ruby хэш-тег # означает метод. Он также может включать префикс имени класса... Класса MyClass#заканчивается


атрибуты и методы-аксессоры

атрибуты-это компоненты класса, к которым можно получить доступ извне объекта. Они известны как свойства во многих других языках программирования. Их значения можно с помощью "точечной нотации", как в имя_объекта.имя атрибута. В отличие от Python и нескольких других языков, Ruby не позволяет обращаться к переменным экземпляра непосредственно извне объекта.

class Car
  def initialize
    @wheels = 4  # This is an instance variable
  end
end

c = Car.new
c.wheels     # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>

в приведенном выше примере c является экземпляром (объектом) класса автомобилей. Мы безуспешно пытались прочитать значение переменной экземпляра wheels извне объекта. Произошло то, что Ruby попытался вызвать метод с именем wheels в объекте c, но такой метод не был определен. Короче, имя_объекта.attribute_name пытается вызвать метод с именем attribute_name внутри объекта. Чтобы получить доступ к значению переменной wheels извне, нам нужно реализовать метод экземпляра с этим именем, который вернет значение этой переменной когда звонили. Это называется методом доступа. В общем контексте программирования обычным способом доступа к переменной экземпляра извне объекта является реализация методов доступа, также известных как методы getter и setter. Геттер позволяет считывать значение переменной, определенной внутри класса, извне, а сеттер позволяет записывать его извне.

в следующем примере мы добавили методы getter и setter в класс Car для доступа к колесам переменная извне объекта. Это не "рубиновый способ" определения геттеров и сеттеров; он служит только для иллюстрации того, что делают методы геттера и сеттера.

class Car
  def wheels  # getter method
    @wheels
  end

  def wheels=(val)  # setter method
    @wheels = val
  end
end

f = Car.new
f.wheels = 4  # The setter method was invoked
f.wheels  # The getter method was invoked
# Output: => 4

приведенный выше пример работает, и аналогичный код обычно используется для создания методов getter и setter на других языках. Однако Ruby предоставляет более простой способ сделать это: три встроенных метода, называемых attr_reader, attr_writer и attr_acessor. Метод attr_reader делает переменную экземпляра читаемой извне, attr_writer делает его доступным для записи, и attr_acessor делает его читать и писать.

приведенный выше пример можно переписать следующим образом.

class Car
  attr_accessor :wheels
end

f = Car.new
f.wheels = 4
f.wheels  # Output: => 4

в приведенном выше примере атрибут wheels будет доступен для чтения и записи извне объекта. Если бы вместо attr_accessor мы использовали attr_reader, он был бы доступен только для чтения. Если бы мы использовали attr_writer, это было бы только для записи. Эти три метода сами по себе не являются геттерами и сеттерами, но при вызове они создают геттер и сеттер. методы сеттера для нас. Это методы, которые динамически (программно) генерируют другие методы; это называется метапрограммированием.

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

возможен доступ (чтение и запись) переменные экземпляра извне объекта с помощью встроенных методов instance_variable_get и instance_variable_set. Однако это редко оправданно и обычно плохая идея, поскольку обход инкапсуляции имеет тенденцию сеять всевозможные хаос.


Хммм. Много хороших ответов. Вот мои несколько центов.

  • attr_accessor - Это простой метод, который помогает нам в уборке(высыхания) до повторять getter and setter методы.

  • чтобы мы могли больше сосредоточиться на написании бизнес-логики и не беспокоиться о сеттерах и геттерах.


основные возможности attr_accessor над другими является возможность доступа к данным из других файлов.
Таким образом, у вас обычно есть attr_reader или attr_writer, но хорошей новостью является то, что Ruby позволяет объединить эти два вместе с attr_accessor. Я думаю об этом как мой идти метод потому что он более хорошо округлен или универсален. Кроме того, имейте в виду, что в Rails это устраняется, потому что он делает это для вас в задней части. Так другими словами: вам лучше использовать attr_acessor над двумя другими, потому что вам не нужно беспокоиться о том, чтобы быть конкретным, аксессор охватывает все это. Я знаю, что это скорее общее объяснение, но оно помогло мне как новичку.

надеюсь, что это помогло!