Что такое attr_accessor в Ruby? - PullRequest
965 голосов
/ 07 декабря 2010

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

Ответы [ 19 ]

2227 голосов
/ 07 декабря 2010

Допустим, у вас есть класс 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

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

class Person
  attr_accessor :name
end

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

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

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.

122 голосов
/ 07 декабря 2010

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

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

Потребность в attr_accessor и друзьях, ну, в общем:

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

  2. Boilerplate отстой

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


1 Это не совсем верно, и есть некоторые "методы" вокруг этого , но нет синтаксической поддержки для "public"переменная экземпляра "access.

65 голосов
/ 07 декабря 2010

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
37 голосов
/ 07 декабря 2010

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

attr_accessor :foo

является сокращением для:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

это не что иное, как метод получения / установки объекта

21 голосов
/ 07 декабря 2010

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

17 голосов
/ 07 декабря 2010

Это просто метод, который определяет методы получения и установки для переменных экземпляра. Примером реализации будет:

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
14 голосов
/ 02 мая 2016

Простое объяснение без кода

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

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

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

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

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

Значение атрибутов чтения и записи:

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

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

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

Объекты внутри класса могут легко обращаться друг к другу

  • С другой стороны, если вы уже были внутри ЦРУ, то вы могли бы легко вызвать своего сотрудника ЦРУ в Кабуле, потому что эта информация легко доступна, если вы уже внутри. Но если вы вне ЦРУ, вам просто не будет предоставлен доступ: вы не сможете узнать, кто они (доступ для чтения), и вы не сможете изменить свою миссию (напишите доступ).

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

13 голосов
/ 08 февраля 2015

Если вы знакомы с концепцией ООП, вы должны быть знакомы с методами получения и установки.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"
12 голосов
/ 16 сентября 2015

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

Метод инициализации

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

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


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

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

В приведенном выше коде мы устанавливаем имя «Денис», используя метод инициализации, передав Деннису через параметр в «Инициализация».Если бы мы хотели установить имя без метода инициализации, мы могли бы сделать это следующим образом:

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 с использованием person.name, а неустановка значений при инициализации объекта.

Оба «метода» выполнения этой работы, но инициализация экономят нам время и строки кода.

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

Получатели, сеттеры (attr_reader, attr_writer, attr_accessor)

Получатели, 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» и «amount» в экземпляре Item «example».«Put example.item_name» и «example.quantity» вернут (или «получат») значение для параметров, переданных в «example», и отобразят их на экране.

К счастью в 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 состояний, относящихся к классу Item?Код быстро стал бы длинным.

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

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

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

Приведенный ниже код является примером использования метода установки для объявления значения 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, сохраняя вам еще одну строку кода.

10 голосов
/ 10 июля 2014

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

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

Немного более обобщенно, но вот как это у меня получилось:

Дано:

class Person
end

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

Так что, если мы тогда:

baby = Person.new

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

baby.name = "Ruth"

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

НО мы можем использовать любой из данных методов (см. Предыдущие ответы) как способ сказать: «Экземпляр класса Person (baby) может теперь иметь атрибут с именем« name » поэтому у нас есть не только синтаксический способ получения и установки этого имени, но и для нас это имеет смысл ».

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

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