Я насилу розуміючи attr_accessor
в Рубіні .
Може хтось мені це пояснить?
git
має нічого спільного attr_accessor
. Git - це програмне забезпечення для управління версіями, тоді attr_accessor
як це метод у Ruby .
Я насилу розуміючи attr_accessor
в Рубіні .
Може хтось мені це пояснить?
git
має нічого спільного attr_accessor
. Git - це програмне забезпечення для управління версіями, тоді attr_accessor
як це метод у Ruby .
Відповіді:
Скажімо, у вас клас 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
в нашому об'єкті особи буде встановлена так само, як коли ми це зробили вручну, тож ви можете використовувати її в інших методах.
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
методи насправді генерують для вас методи, читайте інші відповіді, книги, рубінові документи.
attr_accessor
це метод, викликаний у поточному класі, і :name
це параметр, який ви передаєте цьому методу. Це не особливий синтаксис, це виклик простого методу. Якби ви дали йому @name
змінну, це не мало б сенсу, тому що @name міститиме nil
. Так було б як писати attr_accessor nil
. Ви не передаєте йому змінну, яку вона повинна створити, ви передаєте ім'я, яке ви хочете, щоб змінна була викликана.
name
і змінна - @name
це не одне і те ж. Не плутайте їх. Ви маєте змінну екземпляра @name
у своєму класі, і ви визначаєте attr_reader :name
можливість читати її ззовні. Без attr_reader
цього немає простого способу отримати доступ @name
за межами свого класу.
attr_accessor - це лише метод . (Посилання має надати більш детальну інформацію про те, як воно працює - перегляньте пари створених методів, а підручник повинен показати вам, як ним користуватися.)
Хитрість полягає в тому, що class
це не визначення в Ruby (це "просто визначення" в таких мовах, як C ++ і Java), але це вираження, яке оцінює . Саме під час цієї оцінки, коли attr_accessor
викликається метод, який, у свою чергу, модифікує поточний клас - пам’ятайте неявний приймач:, self.attr_accessor
де self
в цьому пункті знаходиться «відкритий» об’єкт класу.
Потреба attr_accessor
і друзі, це добре:
Ruby, як і Smalltalk, не дозволяє отримати доступ до змінних примірників поза методами 1 для цього об'єкта. Тобто, змінні екземпляри не можуть бути доступні у x.y
формі, як це прийнято, скажімо, Java або навіть Python. У Ruby y
завжди приймається як повідомлення для відправки (або "метод для виклику"). Таким чином, attr_*
методи створюють обгортки, які проксі-екземпляр @variable
отримують доступ через динамічно створені методи.
Котел відсмоктує
Сподіваюсь, це пояснює деякі дрібниці. Щасливе кодування.
1 Це не зовсім вірно, і навколо цього є деякі "прийоми" , але немає підтримки синтаксису для доступу до "змінної публічного екземпляра".
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
дуже просто:
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
Більшість наведених відповідей використовують код. Це пояснення намагається відповісти на це, не використовуючи аналогію / історію:
Зовнішні сторони не можуть отримати доступ до внутрішніх секретів ЦРУ
Уявімо собі справді таємне місце: ЦРУ. Ніхто не знає, що відбувається в ЦРУ, окрім людей всередині ЦРУ. Іншими словами, зовнішні люди не можуть отримати доступ до будь-якої інформації в ЦРУ. Але оскільки непогано мати організацію, яка є повністю секретною, певна інформація надається зовнішньому світу - лише те, про що ЦРУ хоче зрозуміти, звичайно, всі: наприклад, директор ЦРУ, наскільки екологічно чистий цей відділ порівнюється для всіх інших урядових відомств і т.д.
Якщо ви перебуваєте за межами ЦРУ, ви можете отримати доступ лише до тієї інформації, яку вона зробила доступною для громадськості. Або використовувати мову CIA, ви можете отримати доступ лише до інформації, яка "очищена".
Інформація, яку ЦРУ хоче зробити доступною для широкої громадськості за межами ЦРУ, називається: атрибути.
Значення ознак читання та запису:
У випадку ЦРУ більшість атрибутів "лише для читання". Це означає, що якщо ви є стороною зовнішньої організації ЦРУ, ви можете запитати: "хто директор ЦРУ?" і ви отримаєте пряму відповідь. Але те, що ви не можете зробити з атрибутами "лише для читання" - це внести зміни в ЦРУ. наприклад, ви не можете зателефонувати і раптом вирішите, що ви хочете, щоб Кім Кардашян був директором, або що ви хочете, щоб Періс Хілтон була головнокомандувачем.
Якщо атрибути давали вам доступ "писати", то ви можете внести зміни, якщо хочете, навіть якщо ви були за межами. Інакше єдине, що ти можеш зробити - це прочитати.
Іншими словами, аксесуари дозволяють вам здійснювати запити або вносити зміни до організацій, які в іншому випадку не пускають сторонніх людей, залежно від того, чи читають вони чи записують їх.
Об'єкти всередині класу можуть легко отримати доступ один до одного
Точна річ з класами та вашою здатністю отримувати доступ до змінних, властивостей та методів всередині них. HTH! Будь-які запитання, будь ласка, запитайте, і я сподіваюся, що зможу уточнити.
Якщо ви знайомі з концепцією OOP, ви повинні ознайомитися з методом геттера та сетера. 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
Метод Геттера та Сетера в Рубі
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
Я також зіткнувся з цією проблемою і написав дещо тривалу відповідь на це питання. На це вже є чудові відповіді, але кожен, хто шукає більше роз’яснень, сподіваюся, моя відповідь може допомогти
Метод ініціалізації
Ініціалізація дозволяє встановлювати дані до примірника об'єкта при створенні екземпляра, а не встановлювати їх в окремий рядок у вашому коді кожного разу, коли ви створюєте новий екземпляр класу.
class Person
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
У наведеному вище коді ми встановлюємо ім'я "Denis" за допомогою методу ініціалізації, передаючи Dennis через параметр в 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, використовуючи person.name, а не встановлюючи значення при ініціалізації об'єкта.
Обидва «методи» виконання цієї роботи, але ініціалізація економить нам час та рядки коду.
Це єдина робота ініціалізації. Ви не можете закликати ініціалізувати як метод. Щоб фактично отримати значення об’єкта екземпляра, потрібно використовувати getters та setters (attr_reader (get), attr_writer (set) та attr_accessor (обидва)). Детальніше про них див. Нижче.
Getters, Setters (attr_reader, attr_writer, attr_accessor)
Getters, attr_reader: Вся мета getter - повернути значення певної змінної екземпляра. Відвідайте зразок коду нижче, щоб ознайомитись з цим питанням.
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
У наведеному вище коді ви називаєте методи "назва_мента" та "кількість" в екземплярі пункту "Приклад". "Ставить 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? Код швидко отримав би.
Setters, attr_writer: Що спочатку схрестило мене методами сеттера, це те, що в моїх очах, здавалося, виконується ідентична функція методу ініціалізації. Нижче я пояснюю різницю на основі свого розуміння;
Як було сказано раніше, метод ініціалізації дозволяє встановлювати значення для екземпляра об'єкта при створенні об'єкта.
Але що робити, якщо ви хочете встановити значення пізніше, після створення екземпляра, або змінити їх після їх ініціалізації? Це був би сценарій, коли ви використовували б метод сеттера. У чому полягає різниця. Не потрібно «встановлювати» конкретний стан, коли ви спочатку використовуєте метод attr_writer.
Код нижче - це приклад використання методу setter для оголошення значення елемента_імен для цього примірника класу 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"
Код нижче - це повторення прикладу ініціалізації вище, де ми використовуємо ініціалізацію для встановлення об'єктів значення елемента_імен при створенні.
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"
Ми отримуємо помилку, оскільки в Рубіланді об'єкт класу Person - це не те, що асоціюється з або може мати "ім'я" ... ще!
Але ми можемо використовувати будь-який із заданих методів (див. Попередні відповіді) як спосіб сказати: "Екземпляр класу Person ( baby
) тепер може мати атрибут під назвою" name ", тому у нас є не тільки синтаксичний спосіб отримання та встановлення цього імені, але для нас є сенс ».
Знову ж таки, потрапляючи на це питання з дещо іншого та більш загального ракурсу, але я сподіваюся, що це допоможе наступному екземпляру Особи класу, який знайде свій шлях до цієї теми.
Простіше кажучи, це визначить сеттер і геттер для класу.
Зауважте, що
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
.
Приклад:
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
"метод". Тепер ви можете використовувати останні два способи.
$ bankie.balance
$ bankie.owner
Визначає атрибут з ім'ям для цього модуля, де ім'я є name.name2, створюючи змінну екземпляра (@ ім'я) та відповідний метод доступу для його читання. Також створюється метод, який називається name = встановити атрибут.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Для узагальнення доступу до атрибутів aka attr_accessor надає два безкоштовні методи.
Як і на Java, вони називаються геттерами та сетерами.
Багато відповідей показали хороші приклади, тому я просто короткий.
#the_attribute
і
# the_attribute =
У старих рубінових документах хеш-тег # означає метод. Він також може містити префікс назви класу ... MyClass # my_method
Я новачок у рубіні і мусив просто розібратися з розумінням наступних дивацтв. Може допомогти комусь ще в майбутньому. Зрештою, це було, як було сказано вище, де дві функції (def myvar, def myvar =) обидві отримують неявно для доступу до @myvar, але ці методи можуть бути замінені місцевими деклараціями.
class Foo
attr_accessor 'myvar'
def initialize
@myvar = "A"
myvar = "B"
puts @myvar # A
puts myvar # B - myvar declared above overrides myvar method
end
def test
puts @myvar # A
puts myvar # A - coming from myvar accessor
myvar = "C" # local myvar overrides accessor
puts @myvar # A
puts myvar # C
send "myvar=", "E" # not running "myvar =", but instead calls setter for @myvar
puts @myvar # E
puts myvar # C
end
end
Атрибути - це компоненти класу, до яких можна отримати доступ із-за об'єкта. Вони відомі як властивості у багатьох інших мовах програмування. Їх значення доступні за допомогою "позначення крапок", як у object_name.attribute_name. На відміну від 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 - екземпляр (об'єкт) класу Car. Ми безуспішно намагалися прочитати значення змінної екземпляра колеса з-за об'єкта. Що сталося, це те, що Рубі намагався викликати метод, названий колесами, в межах c-об'єкта, але такого методу не було визначено. Коротше кажучи, object_name.attribute_name намагається викликати метод, названий attribute_name всередині об'єкта. Щоб отримати доступ до значення змінної коліс ззовні, нам потрібно реалізувати метод екземпляра під цим іменем, який повертає значення цієї змінної при виклику. Це називається методом аксесуара. У загальному контексті програмування звичайним способом доступу до змінної екземпляра поза об'єктом є реалізація методів accessor, також відомих як методи 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
Наведений вище приклад працює та подібний код зазвичай використовується для створення методів геттера та сеттера іншими мовами. Однак 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
У наведеному вище прикладі атрибут колеса буде читабельним та доступним для запису ззовні об'єкта. Якби замість attr_accessor ми використовували attr_reader, він буде лише для читання. Якби ми використовували attr_writer, це було б лише для запису. Ці три методи самі по собі не є геттерами та сеттерами, але, коли їх називають, вони створюють для нас методи геттера та сеттера. Це методи, що динамічно (програмно) генерують інші методи; це називається метапрограмуванням.
Перший (довший) приклад, в якому не використовуються вбудовані методи Ruby, слід використовувати лише тоді, коли в методах getter і setter потрібен додатковий код. Наприклад, методу встановлення може знадобитися перевірити дані або зробити якийсь обчислення, перш ніж призначити значення змінній екземпляра.
Доступ до змінних екземплярів (читання та запису) можна використовувати з-за меж об'єкта, використовуючи вбудовані методи instance_variable_get та instance_variable_set. Однак це рідко є виправданим і, як правило, поганою ідеєю, оскільки обхід капсуляції має тенденцію спричиняти всілякі хаоси.
Хммм. Багато хороших відповідей. Ось мої кілька центів на ньому.
attr_accessor
це простий метод, який допомагає нам очистити ( висушити ) повторюваніgetter and setter
методи.
Так що ми можемо більше зосередитись на написанні ділової логіки і не турбуватися про сетерів та промовців.
Основна функціональність attr_accessor над іншими - це можливість доступу до даних з інших файлів.
Таким чином, у вас зазвичай є attr_reader або attr_writer, але гарна новина полягає в тому, що Ruby дозволяє комбінувати ці два разом з attr_accessor. Я вважаю це своїм методом, тому що він більш закруглений або універсальний. Також майте на увазі, що в Rails це усувається, оскільки це робиться для вас із зворотнього боку. Отже, іншими словами: вам краще використовувати attr_acessor над іншими двома, тому що вам не потрібно турбуватися про конкретність, аксесуар охоплює все це. Я знаю, що це більше загальне пояснення, але це допомогло мені як початківцю.
Сподіваюся, це допомогло!