Mam trudności ze zrozumieniem attr_accessor
w języku Ruby .
Czy ktoś może mi to wyjaśnić?
git
nie ma z tym nic wspólnego attr_accessor
. Git to oprogramowanie do kontroli wersji, podczas gdy attr_accessor
jest metodą w Ruby .
Mam trudności ze zrozumieniem attr_accessor
w języku Ruby .
Czy ktoś może mi to wyjaśnić?
git
nie ma z tym nic wspólnego attr_accessor
. Git to oprogramowanie do kontroli wersji, podczas gdy attr_accessor
jest metodą w Ruby .
Odpowiedzi:
Powiedzmy, że masz klasę Person
.
class Person
end
person = Person.new
person.name # => no method error
Oczywiście nigdy nie zdefiniowaliśmy metody name
. Zróbmy to.
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
Aha, możemy odczytać imię, ale to nie znaczy, że możemy je przypisać. To są dwie różne metody. Ten pierwszy nazywa się czytelnikiem, a drugi pisarzem . Nie stworzyliśmy jeszcze pisarza, więc zróbmy to.
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"
Niesamowite. Teraz możemy pisać i odczytywać zmienne instancji @name
za pomocą metod czytnika i zapisu . Tyle że dzieje się to tak często, dlaczego marnować czas na pisanie tych metod za każdym razem? Możemy to zrobić łatwiej.
class Person
attr_reader :name
attr_writer :name
end
Nawet to może stać się powtarzalne. Jeśli chcesz zarówno czytnika, jak i pisarza, użyj akcesorium!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
Działa w ten sam sposób! I zgadnij co: zmienna instancji @name
w naszym obiekcie osoby zostanie ustawiona tak samo jak wtedy, gdy zrobiliśmy to ręcznie, więc możesz użyć jej w innych metodach.
class Person
attr_accessor :name
def greeting
"Hello #{@name}"
end
end
person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"
Otóż to. Aby zrozumieć, jak attr_reader
, attr_writer
, i attr_accessor
metody faktycznie generuje metody, Przeczytaj inne odpowiedzi, książki, dokumenty Ruby.
attr_accessor
jest to metoda wywoływana w bieżącej klasie i :name
parametr przekazywany do tej metody. To nie jest specjalna składnia, to proste wywołanie metody. Jeśli miałbyś nadać jej @name
zmienną, nie miałoby to sensu, ponieważ @ nazwa zawierałaby nil
. To byłoby jak pisanie attr_accessor nil
. Nie przekazujesz jej zmiennej, którą musi utworzyć, przekazujesz nazwę, którą chcesz wywołać zmienną.
name
i zmienna @name
to nie to samo. Nie pomyl ich. W @name
swojej klasie masz zmienną instancji i określasz, że możesz attr_reader :name
ją odczytać z zewnątrz. Bez tego attr_reader
nie ma prostego sposobu na uzyskanie dostępu @name
poza klasą.
attr_accessor to tylko metoda . (Link powinien zapewnić lepszy wgląd w to, jak to działa - spójrz na wygenerowane pary metod, a samouczek powinien pokazać, jak z niego korzystać.)
Sztuka polega na tym class
nie jest to definicja w Rubim (jest to „tylko definicja” w językach takich jak C ++ i Java), ale jest to wyrażenie, które ocenia . To właśnie podczas tej oceny attr_accessor
wywoływana jest metoda, która z kolei modyfikuje bieżącą klasę - pamiętaj niejawny odbiornik: self.attr_accessor
gdzie self
jest w tym momencie obiekt klasy „otwartej”.
Potrzeba attr_accessor
i przyjaciele to:
Ruby, podobnie jak Smalltalk, nie pozwala na dostęp do zmiennych instancji poza metodami 1 dla tego obiektu. Oznacza to, że zmienne instancji nie mogą być dostępne w takiej x.y
formie, jak to zwykle jest powiedziane, Java, a nawet Python. W Ruby y
jest zawsze traktowany jako wiadomość do wysłania (lub „metoda wywołania”). W ten sposób attr_*
metody tworzą opakowania, które zastępują @variable
dostęp do instancji za pomocą dynamicznie tworzonych metod.
Kocioł jest do bani
Mam nadzieję, że to wyjaśnia niektóre małe szczegóły. Szczęśliwego kodowania.
1 Nie jest to do końca prawdą i istnieją wokół tego pewne „techniki” , ale nie ma obsługi składni dla dostępu do „zmiennej instancji publicznej”.
attr_accessor
jest (jak stwierdzono @pst) tylko metodą. Tworzy dla ciebie więcej metod.
Więc ten kod tutaj:
class Foo
attr_accessor :bar
end
jest równoważne z tym kodem:
class Foo
def bar
@bar
end
def bar=( new_value )
@bar = new_value
end
end
Możesz napisać tę metodę samodzielnie w 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
i znalazłem tutaj! Chociaż rozwiązało to mój problem, ale jestem ciekawy, gdzie (książka / oficjalny dokument) mogę znaleźć taki przykład wdrożenia?
attr_accessor
jest bardzo proste:
attr_accessor :foo
jest skrótem do:
def foo=(val)
@foo = val
end
def foo
@foo
end
jest niczym więcej niż getter / setter dla obiektu
Zasadniczo fałszują publicznie dostępne atrybuty danych, których Ruby nie ma.
Jest to tylko metoda definiująca metody pobierające i ustawiające dla przykładowych zmiennych. Przykładową implementacją byłoby:
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
Większość powyższych odpowiedzi używa kodu. To wyjaśnienie próbuje odpowiedzieć na to pytanie bez użycia jakiejkolwiek analogii / historii:
Strony zewnętrzne nie mają dostępu do wewnętrznych tajemnic CIA
Wyobraźmy sobie naprawdę tajne miejsce: CIA. Nikt nie wie, co dzieje się w CIA, poza ludźmi wewnątrz CIA. Innymi słowy, osoby zewnętrzne nie mogą uzyskać dostępu do żadnych informacji w CIA. Ale ponieważ nie jest dobrze mieć całkowicie tajną organizację, pewne informacje są udostępniane światu zewnętrznemu - tylko rzeczy, o których CIA chce oczywiście wiedzieć wszyscy: np. Dyrektor CIA, jak przyjazny dla środowiska ten departament jest porównywany do wszystkich innych departamentów rządowych itp. Inne informacje: np. kim są tajni agenci w Iraku lub Afganistanie - tego rodzaju rzeczy prawdopodobnie pozostaną tajemnicą przez następne 150 lat.
Jeśli jesteś poza CIA, możesz uzyskać dostęp tylko do informacji, które udostępniła publicznie. Lub, aby użyć języka CIA, możesz uzyskać dostęp tylko do informacji „wyczyszczonych”.
Informacje, które CIA chce udostępnić ogółowi społeczeństwa poza CIA, nazywane są: atrybutami.
Znaczenie atrybutów odczytu i zapisu:
W przypadku CIA większość atrybutów to „tylko do odczytu”. Oznacza to, że jeśli jesteś stroną spoza CIA, możesz zapytać: „kto jest dyrektorem CIA?” a otrzymasz prostą odpowiedź. Ale nie możesz zrobić z atrybutami „tylko do odczytu”, aby wprowadzić zmiany w CIA. np. nie możesz zadzwonić i nagle zdecydować , że chcesz, aby Kim Kardashian został dyrektorem, lub że chcesz, żeby Paris Hilton była naczelnym dowódcą.
Jeśli atrybuty dały ci dostęp do „zapisu”, możesz wprowadzić zmiany, jeśli chcesz, nawet jeśli jesteś na zewnątrz. W przeciwnym razie jedyne, co możesz zrobić, to przeczytać.
Innymi słowy, akcesory pozwalają zadawać zapytania lub wprowadzać zmiany w organizacjach, które w przeciwnym razie nie wpuszczają osób zewnętrznych, w zależności od tego, czy są to czytniki, czy zapisujące.
Przedmioty w klasie mogą mieć do siebie łatwy dostęp
Dokładnie to samo z klasami i twoją możliwością dostępu do zmiennych, właściwości i metod w nich zawartych. HTH! Wszelkie pytania proszę zadawać i mam nadzieję, że wyjaśnię.
Jeśli znasz koncepcję OOP, musisz zapoznać się z metodą getter i setter. attr_accessor robi to samo w Ruby.
Getter and Setter w ogólności
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"
Metoda Settera
def name=(val)
@name = val
end
Metoda Gettera
def name
@name
end
Metoda Gettera i Settera w Rubim
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
Ja również zmierzyłem się z tym problemem i napisałem dość długą odpowiedź na to pytanie. Istnieją już świetne odpowiedzi na ten temat, ale każdy, kto szuka dodatkowych wyjaśnień, mam nadzieję, że moja odpowiedź może pomóc
Zainicjuj metodę
Inicjalizacja pozwala ustawić dane dla instancji obiektu po utworzeniu instancji zamiast konieczności ustawiania ich w osobnej linii w kodzie za każdym razem, gdy tworzysz nową instancję klasy.
class Person
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
W powyższym kodzie ustawiamy nazwę „Denis” przy użyciu metody inicjalizacji, przekazując Dennisowi przez parametr w opcji Inicjuj. Gdybyśmy chcieli ustawić nazwę bez metody inicjalizacji, moglibyśmy to zrobić w następujący sposób:
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
W powyższym kodzie ustawiamy nazwę, wywołując metodę setter attr_accessor przy użyciu person.name, a nie ustawiając wartości przy inicjalizacji obiektu.
Obie „metody” wykonywania tej pracy, ale inicjalizacja oszczędzają nam czas i wiersze kodu.
To jest jedyne zadanie inicjalizacji. Nie można wywoływać inicjalizacji jako metody. Aby faktycznie uzyskać wartości obiektu instancji, musisz użyć metod pobierających i ustawiających (attr_reader (get), attr_writer (set) i attr_accessor (oba)). Zobacz poniżej więcej szczegółów na ich temat.
Getters, Setters (attr_reader, attr_writer, attr_accessor)
Getters, attr_reader: Celem gettera jest zwrócenie wartości określonej zmiennej instancji. Odwiedź poniższy przykładowy kod, aby uzyskać informacje na temat tego.
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
W powyższym kodzie wywołujesz metody „item_name” i „ilość” w przypadku elementu „example”. „Puts example.item_name” i „example.quantity” zwróci (lub „get”) wartość parametrów przekazanych do „example” i wyświetli je na ekranie.
Na szczęście w Ruby istnieje nieodłączna metoda, która pozwala nam napisać ten kod bardziej zwięźle; metoda attr_reader. Zobacz kod poniżej;
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
Ta składnia działa dokładnie w ten sam sposób, tyle że oszczędza nam sześć linii kodu. Wyobraź sobie, że miałeś jeszcze 5 stanów przypisywanych do klasy Przedmiotów? Kod szybko się wydłuży.
Setters, attr_writer: Na początku spotkałem się z metodami setter, ponieważ w moich oczach wydawało się, że pełnią one identyczną funkcję jak metoda inicjalizacji. Poniżej wyjaśniam różnicę na podstawie mojego zrozumienia;
Jak wspomniano wcześniej, metoda inicjalizacji umożliwia ustawienie wartości dla wystąpienia obiektu podczas tworzenia obiektu.
Ale co, jeśli chcesz ustawić wartości później, po utworzeniu instancji, lub zmienić je po ich zainicjowaniu? Byłby to scenariusz, w którym użyłbyś metody ustawiającej. TO JEST RÓŻNICA. Nie musisz „ustawiać” określonego stanu, kiedy początkowo używasz metody attr_writer.
Poniższy kod jest przykładem użycia metody setter do zadeklarowania wartości item_name dla tego wystąpienia klasy Item. Zauważ, że nadal używamy metody getter attr_reader, abyśmy mogli pobrać wartości i wydrukować je na ekranie, na wypadek, gdybyś chciał przetestować kod samodzielnie.
class Item
attr_reader :item_name
def item_name=(str)
@item_name = (str)
end
end
Poniższy kod jest przykładem użycia attr_writer do ponownego skrócenia naszego kodu i zaoszczędzenia czasu.
class Item
attr_reader :item_name
attr_writer :item_name
end
item = Item.new
puts item.item_name = "TV"
Poniższy kod jest powtórzeniem powyższego przykładu inicjalizacji, w którym za pomocą funkcji inicjalizacji ustawia się wartość obiektów item_name podczas tworzenia.
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: Wykonuje funkcje zarówno attr_reader, jak i attr_writer, oszczędzając ci jeszcze jedną linię kodu.
Myślę, że częścią tego, co myli nowych Rubyistów / programistów (takich jak ja), jest:
„Dlaczego nie mogę po prostu powiedzieć instancji, że ma dowolny atrybut (np. Nazwę) i nadać temu atrybutowi wartość za jednym zamachem?”
Trochę bardziej uogólniony, ale tak to dla mnie kliknęło:
Dany:
class Person
end
Nie zdefiniowaliśmy osoby jako czegoś, co może mieć imię lub inne atrybuty w tym zakresie.
Jeśli więc:
baby = Person.new
... i spróbuj nadać im nazwę ...
baby.name = "Ruth"
Otrzymujemy błąd , ponieważ w Rubyland klasa Person obiektu nie jest coś, co jest związane z lub zdolne do posiadania „name” ... jeszcze!
ALE możemy użyć dowolnej z podanych metod (patrz poprzednie odpowiedzi) jako sposobu na powiedzenie: „Instancja klasy Person ( baby
) może teraz mieć atrybut o nazwie„ name ”, dlatego mamy nie tylko składniowy sposób uzyskiwania i ustawienie tej nazwy, ale ma to sens. ”
Znów trafiam w to pytanie z nieco innej i bardziej ogólnej perspektywy, ale mam nadzieję, że to pomoże następnej instancji klasy Osoba, która znajdzie drogę do tego wątku.
Po prostu zdefiniuje on ustawiającego i pobierającego dla klasy.
Zauważ, że
attr_reader :v is equivalant to
def v
@v
end
attr_writer :v is equivalant to
def v=(value)
@v=value
end
Więc
attr_accessor :v which means
attr_reader :v; attr_writer :v
są równoważne w celu zdefiniowania settera i gettera dla klasy.
Innym sposobem na zrozumienie tego jest ustalenie, jaki kod błędu eliminuje poprzez posiadanie attr_accessor
.
Przykład:
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
Dostępne są następujące metody:
$ bankie = BankAccout.new("Iggy")
$ bankie
$ bankie.deposit(100)
$ bankie.withdraw(5)
Następujące metody generują błąd:
$ bankie.owner #undefined method `owner'...
$ bankie.balance #undefined method `balance'...
owner
i balance
nie są technicznie metodą , ale atrybutem. Klasa BankAccount nie ma def owner
i def balance
. Jeśli tak, możesz użyć dwóch poniższych poleceń. Ale tych dwóch metod nie ma. Możesz jednak uzyskać dostęp do atrybutów tak, jakbyś miał dostęp do metody za pośrednictwem attr_accessor
!! Stąd słowoattr_accessor
. Atrybut. Accessor. Uzyskuje dostęp do atrybutów tak, jakbyś miał dostęp do metody.
Dodanie attr_accessor :balance, :owner
pozwala na czytanie i pisanie balance
oraz owner
„metodę”. Teraz możesz użyć 2 ostatnich metod.
$ bankie.balance
$ bankie.owner
Definiuje nazwany atrybut dla tego modułu, gdzie nazwa to symbol.id2name, tworząc zmienną instancji (@nazwa) i odpowiednią metodę dostępu, aby ją odczytać. Tworzy również metodę o nazwie name = w celu ustawienia atrybutu.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Podsumowując atrybut accessor aka attr_accessor daje dwie bezpłatne metody.
Podobnie jak w Javie, nazywane są modułami pobierającymi i ustawiającymi.
Wiele odpowiedzi pokazało dobre przykłady, więc powiem krótko.
# atrybut
i
# the_attribute =
W starych dokumentach ruby hash tag # oznacza metodę. Może także zawierać prefiks nazwy klasy ... MyClass # my_method
Jestem nowy w rubinach i musiałem po prostu poradzić sobie ze zrozumieniem następującej dziwności. W przyszłości może pomóc komuś innemu. Ostatecznie jest tak, jak wspomniano powyżej, gdzie 2 funkcje (def myvar, def myvar =) obie uzyskują niejawnie dostęp do @myvar, ale metody te można zastąpić deklaracjami lokalnymi.
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
Atrybuty są komponentami klasy, do których można uzyskać dostęp spoza obiektu. Są znane jako właściwości w wielu innych językach programowania. Ich wartości są dostępne za pomocą „notacji kropkowej”, jak w nazwie nazwa_obiektu. Nazwa_atrybutu. W przeciwieństwie do Pythona i kilku innych języków, Ruby nie pozwala na dostęp do zmiennych instancji bezpośrednio z zewnątrz obiektu.
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>
W powyższym przykładzie c jest instancją (obiektem) klasy Car. Próbowaliśmy bezskutecznie odczytać wartość zmiennej instancji koła z zewnątrz obiektu. Stało się tak, że Ruby próbowała wywołać metodę o nazwie koła w obiekcie c, ale taka metoda nie została zdefiniowana. Krótko mówiąc, nazwa_obiektu. Nazwa_atrybutu próbuje wywołać metodę o nazwie nazwa_atrybutu w obiekcie. Aby uzyskać dostęp do wartości zmiennej koła z zewnątrz, musimy zaimplementować metodę instancji o tej nazwie, która zwróci wartość tej zmiennej po wywołaniu. To się nazywa metoda akcesorium. W ogólnym kontekście programowania typowym sposobem uzyskania dostępu do zmiennej instancji spoza obiektu jest zaimplementowanie metod akcesorów, znanych również jako metody pobierające i ustawiające.
W poniższym przykładzie dodaliśmy metody getter i setter do klasy Car, aby uzyskać dostęp do zmiennej koła spoza obiektu. To nie jest „rubinowy sposób” definiowania getterów i seterów; służy jedynie zilustrowaniu działania metod pobierających i ustawiających.
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
Powyższy przykład działa i podobny kod jest powszechnie używany do tworzenia metod pobierających i ustawiających w innych językach. Ruby zapewnia jednak prostszy sposób: trzy wbudowane metody o nazwie attr_reader, attr_writer i attr_acessor. Metoda attr_reader sprawia, że zmienna instancji jest czytelna z zewnątrz, attr_writer umożliwia jej zapis, a attr_acessor czyni ją czytelną i zapisywalną.
Powyższy przykład można przepisać w ten sposób.
class Car
attr_accessor :wheels
end
f = Car.new
f.wheels = 4
f.wheels # Output: => 4
W powyższym przykładzie atrybut koła będzie czytelny i zapisywalny z zewnątrz obiektu. Jeśli zamiast attr_accessor użyjemy attr_reader, będzie to tylko do odczytu. Gdybyśmy użyli attr_writer, byłoby to tylko do zapisu. Te trzy metody same w sobie nie są metodami pobierającymi i ustawiającymi, ale po wywołaniu tworzą dla nas metody pobierające i ustawiające. Są to metody, które dynamicznie (programowo) generują inne metody; to się nazywa metaprogramowanie.
Pierwszy (dłuższy) przykład, który nie wykorzystuje wbudowanych metod Ruby, powinien być używany tylko wtedy, gdy wymagany jest dodatkowy kod w metodach pobierających i ustawiających. Na przykład metoda ustawiająca może wymagać weryfikacji danych lub wykonania obliczeń przed przypisaniem wartości do zmiennej instancji.
Dostęp do zmiennych instancji (odczyt i zapis) można uzyskać z zewnątrz obiektu, korzystając z wbudowanych metod zestaw_instancji_wystąpienia i zestawu_instancji_wystąpienia. Jest to jednak rzadko uzasadnione i zwykle zły pomysł, ponieważ ominięcie enkapsulacji powoduje zwykle spustoszenie.
Hmmm. Wiele dobrych odpowiedzi. Oto moje kilka centów na ten temat.
attr_accessor
to prosta metoda, która pomaga nam w czyszczeniu ( osuszaniu ) powtarzaniagetter and setter
metod.
Abyśmy mogli bardziej skoncentrować się na pisaniu logiki biznesowej i nie martwić się o ustawiających i pobierających.
Główną funkcjonalnością attr_accessor nad pozostałymi jest możliwość dostępu do danych z innych plików.
Zwykle masz attr_reader lub attr_writer, ale dobrą wiadomością jest to, że Ruby pozwala łączyć te dwa elementy z attr_accessor. Myślę, że to moja metoda ponieważ jest bardziej zaokrąglona lub wszechstronna. Pamiętaj też, że w Railsach jest to eliminowane, ponieważ robi to za Ciebie w back-endie. Innymi słowy: lepiej jest użyć attr_acessor w porównaniu do pozostałych dwóch, ponieważ nie musisz się martwić, że jesteś konkretny, akcesorium to wszystko obejmuje. Wiem, że to bardziej ogólne wyjaśnienie, ale pomogło mi to jako początkującym.
Mam nadzieję, że to pomogło!