@user.update_languages(params[:language][:language1],
params[:language][:language2],
params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------"
+ lang_errors.full_messages.inspect
if params[:user]
@user.state = params[:user][:state]
success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------"
+ lang_errors.full_messages.inspect
if lang_errors.full_messages.empty?
@user
obiekt dodaje błędy do lang_errors
zmiennej w update_lanugages
metodzie. kiedy wykonuję zapis @user
obiektu, tracę błędy, które początkowo były przechowywane w lang_errors
zmiennej.
Chociaż to, co próbuję zrobić, byłoby bardziej włamaniem (co wydaje się nie działać). Chciałbym zrozumieć, dlaczego wartości zmiennych są wypłukiwane. Rozumiem przekazanie przez odniesienie, więc chciałbym wiedzieć, jak wartość może być utrzymywana w tej zmiennej bez wymywania.
Odpowiedzi:
W tradycyjnej terminologii Ruby jest ściśle przekazywana według wartości . Ale tak naprawdę nie o to tu pytasz.
Ruby nie ma pojęcia o wartości czystej, bez odniesienia, więc z pewnością nie można przekazać żadnej metody. Zmienne są zawsze odniesieniami do obiektów. Aby uzyskać obiekt, który nie zmieni się spod ciebie, musisz zduplikować lub sklonować przekazany obiekt, dając w ten sposób obiekt, do którego nikt inny nie ma odniesienia. (Nawet to nie jest kuloodporne - obie standardowe metody klonowania wykonują płytką kopię, więc zmienne instancji klonu nadal wskazują na te same obiekty, które zrobiły oryginały. Jeśli obiekty, do których odwołują się ivars, mutują, to będzie nadal pojawiają się w kopii, ponieważ odnoszą się do tych samych obiektów).
źródło
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.Pozostałe odpowiedzi są prawidłowe, ale przyjaciel poprosił mnie, żebym mu to wytłumaczył, a tak naprawdę sprowadza się to do tego, jak Ruby obsługuje zmienne, więc pomyślałem, że podzielę się kilkoma prostymi zdjęciami / wyjaśnieniami, które dla niego napisałem (przepraszam za długość i prawdopodobnie pewne uproszczenia):
P1: Co się stanie, gdy przypiszesz nową zmienną
str
do wartości'foo'
?Odp .: Wywoływana
str
jest etykieta wskazująca obiekt'foo'
, który dla stanu tego interpretera języka Ruby znajduje się w miejscu pamięci2000
.P2: Co się stanie, gdy przypiszesz istniejącą zmienną
str
do nowego obiektu za pomocą=
?Odp .: Etykieta
str
wskazuje teraz na inny obiekt.Q3: Co się dzieje, kiedy przypisać nową zmienną
=
dostr
?Odp .: Tworzona jest nowa etykieta o nazwie,
str2
która wskazuje na ten sam obiekt costr
.P4: Co się stanie, jeśli obiekt odwołuje się do
str
istr2
zostanie zmieniony?Odp .: Obie etykiety nadal wskazują ten sam obiekt, ale sam obiekt zmutował (jego zawartość zmieniła się na coś innego).
Jak to się ma do pierwotnego pytania?
Jest to w zasadzie to samo, co dzieje się w Q3 / Q4; metoda otrzymuje własną prywatną kopię zmiennej / label (
str2
), która jest do niej przekazywana (str
). Nie może zmienić obiektu, na którystr
wskazuje etykieta , ale może zmienić zawartość obiektu, do którego odwołują się oboje, aby zawierał jeszcze:źródło
Ruby używa „przekaż odniesienie do obiektu”
(Korzystanie z terminologii Python.)
Powiedzenie, że Ruby używa „przekaż przez wartość” lub „przekaż przez referencję”, nie jest tak naprawdę wystarczająco opisowe, aby było pomocne. Myślę, że jak większość ludzi wie to w dzisiejszych czasach, terminologia („wartość” vs „referencja”) pochodzi z C ++.
W C ++ „przekazanie przez wartość” oznacza, że funkcja pobiera kopię zmiennej, a wszelkie zmiany w kopii nie zmieniają oryginału. Dotyczy to również obiektów. Jeśli przekażesz zmienną obiektową według wartości, cały obiekt (w tym wszystkie jego elementy) zostanie skopiowany, a wszelkie zmiany w elementach członkowskich nie zmienią tych elementów w oryginalnym obiekcie. (Jest inaczej, jeśli przekażesz wskaźnik wartości, ale Ruby i tak nie ma wskaźników, AFAIK.)
Wynik:
W C ++ „przekazanie przez odniesienie” oznacza, że funkcja uzyskuje dostęp do oryginalnej zmiennej. Może przypisać zupełnie nową literalną liczbę całkowitą, a oryginalna zmienna również będzie miała tę wartość.
Wynik:
Ruby używa przekazywania przez wartość (w sensie C ++), jeśli argument nie jest obiektem. Ale w Ruby wszystko jest przedmiotem, więc tak naprawdę w Ruby nie ma przekazywania wartości w sensie C ++.
W Ruby używa się „pass by object reference” (w celu użycia terminologii Pythona):
Dlatego Ruby nie używa „przekaż przez referencję” w sensie C ++. Jeśli tak, to przypisanie nowego obiektu do zmiennej wewnątrz funkcji spowoduje, że stary obiekt zostanie zapomniany po powrocie funkcji.
Wynik:
* Dlatego w Rubim, jeśli chcesz zmodyfikować obiekt wewnątrz funkcji, ale zapominasz o tych zmianach po powrocie funkcji, musisz jawnie wykonać kopię obiektu przed dokonaniem tymczasowych zmian w kopii.
źródło
def ch(str) str.reverse! end; str="abc"; ch(str); puts str #=> "cba"
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
. Wypisuje „Ruby jest wartością przekazaną”. Ale zmienna wewnątrzfoo
jest ponownie przypisana. Jeślibar
byłaby tablicą, zmiana przypisania nie miałaby wpływubaz
. Czemu?Ruby jest wartością przekazywaną. Zawsze. Bez wyjątków. Nie, jeśli. Żadnych ale.
Oto prosty program, który pokazuje ten fakt:
źródło
Ruby jest wartością przekazywaną w ścisłym tego słowa znaczeniu, ALE wartości są referencjami.
Można to nazwać „ pass-reference-by-value ”. Ten artykuł ma najlepsze wyjaśnienie, jakie przeczytałem: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Przekazywanie według wartości można krótko wyjaśnić w następujący sposób:
Wynikowe zachowanie jest w rzeczywistości kombinacją klasycznych definicji pass-by-reference i pass-by-value.
źródło
Istnieją już świetne odpowiedzi, ale chcę opublikować definicję pary autorytetów na ten temat, ale mam również nadzieję, że ktoś może wyjaśnić, co autorytety Matz (twórca Ruby) i David Flanagan mieli na myśli w swojej doskonałej książce O'Reilly, Język programowania Ruby .
To wszystko ma dla mnie sens aż do ostatniego akapitu, a zwłaszcza do ostatniego zdania. Jest to co najmniej wprowadzające w błąd, a co gorsza. W jaki sposób modyfikacje odwołania do wartości przekazywanej przez wartość mogłyby zmienić obiekt leżący u podstaw?
źródło
Ruby jest przekazywany przez odniesienie. Zawsze. Bez wyjątków. Nie, jeśli. Żadnych ale.
Oto prosty program, który pokazuje ten fakt:
źródło
bar
metodzie. Po prostu modyfikujesz obiekt, na który wskazuje odwołanie , ale nie samo odwołanie. Jedynym sposobem modyfikowania referencji w Ruby jest przypisanie. Nie można modyfikować referencji, wywołując metody w Rubim, ponieważ metody można wywoływać tylko dla obiektów, a referencje nie są obiektami w Rubim. Twój przykładowy kod pokazuje, że Ruby ma wspólny stan mutable (który nie jest tutaj omawiany), nie robi to jednak nic, aby rozróżnić różnicę między wartością pass-by-pass-by-referencją.Parametry są kopią oryginalnego odwołania. Możesz więc zmieniać wartości, ale nie możesz zmienić oryginalnego odwołania.
źródło
Spróbuj tego:--
identyfikator a zawiera identyfikator_obiektu 3 dla obiektu wartości 1, a identyfikator b zawiera identyfikator_obiektu 5 dla obiektu wartości 2.
Zrób to teraz:--
Teraz oba a i b zawierają ten sam identyfikator_obiektu 5, który odnosi się do obiektu wartości 2. Tak więc zmienna Ruby zawiera identyfikatory obiektu, które odnoszą się do obiektów wartości.
Wykonanie następujących czynności powoduje również błąd: -
ale zrobienie tego nie spowoduje błędu: -
Tutaj identyfikator zwraca wartość obiektu 11, którego identyfikator obiektu to 23, tj. ID_obiektu 23 znajduje się w identyfikatorze a, Teraz widzimy przykład za pomocą metody.
arg w foo ma przypisaną wartość x. Wyraźnie pokazuje, że argument jest przekazywany przez wartość 11, a sama wartość 11 będąca obiektem ma unikalny identyfikator obiektu 23.
Zobacz teraz także: -
W tym przypadku identyfikator arg najpierw zawiera identyfikator_obiektu 23 do odwołania 11, a po wewnętrznym przypisaniu do obiektu wartości 12 zawiera identyfikator_obiektu 25. Ale nie zmienia wartości, do której odwołuje się identyfikator x używany w metodzie wywoływania.
Dlatego Ruby jest przekazywany przez wartość, a zmienne Ruby nie zawierają wartości, ale zawierają odwołanie do obiektu wartości.
źródło
Ruby jest interpretowany. Zmienne są odniesieniami do danych, ale nie do samych danych. Ułatwia to użycie tej samej zmiennej dla danych różnych typów.
Przypisanie lhs = rhs następnie kopiuje odwołanie do rhs, a nie danych. Różni się to w innych językach, takich jak C, gdzie przypisanie kopiuje dane do lhs z rhs.
Tak więc dla wywołania funkcji przekazana zmienna, powiedzmy x, jest rzeczywiście kopiowana do zmiennej lokalnej w funkcji, ale x jest referencją. Będą wtedy dwie kopie referencji, obie odwołujące się do tych samych danych. Jeden będzie w dzwoniącym, jeden w funkcji.
Przypisanie funkcji spowoduje skopiowanie nowego odwołania do wersji x funkcji. Po tym wersja x dzwoniącego pozostaje niezmieniona. Jest to nadal odniesienie do oryginalnych danych.
Natomiast użycie metody .replace na x spowoduje, że Ruby wykona kopię danych. Jeśli zastąpi się przed nowymi przypisaniami, to rzeczywiście dzwoniący zobaczy zmiany danych również w swojej wersji.
Podobnie, dopóki oryginalne odwołanie jest taktowane dla przekazywanej zmiennej, zmienne instancji będą takie same, jak wywołujący. W ramach obiektu zmienne instancji zawsze mają najbardziej aktualne wartości referencyjne, niezależnie od tego, czy są one dostarczane przez obiekt wywołujący, czy ustawione w funkcji, do której klasa została przekazana.
„Call by value” lub „call by reference” jest tu mętne z powodu zamieszania związanego z „=” W językach kompilowanych „=” to kopia danych. Tutaj w tym tłumaczonym języku „=” jest kopią referencyjną. W tym przykładzie przekazano referencję, a następnie kopię referencyjną „=”, która blokuje oryginał przekazany w referencji, a następnie ludzie mówią o tym, jakby „=” była kopią danych.
Aby zachować zgodność z definicjami, musimy zachować „.replace”, ponieważ jest to kopia danych. Z perspektywy „.replace” widzimy, że tak naprawdę jest to odniesienie. Ponadto, jeśli przejdziemy przez debugger, zobaczymy, że przekazywane są referencje, ponieważ zmienne są referencjami.
Jeśli jednak musimy zachować wartość „=” jako odniesienie, wówczas rzeczywiście widzimy przekazane dane aż do przypisania, a następnie nie widzimy go już po przypisaniu, podczas gdy dane dzwoniącego pozostają niezmienione. Na poziomie behawioralnym jest to przekazywanie wartości, o ile nie uważamy, że przekazana wartość jest złożona - ponieważ nie będziemy w stanie zachować jej części, zmieniając drugą część w jednym przydziale (jak to przydział) zmienia odniesienie, a oryginał wychodzi poza zakres). Będzie też brodawka, w tym przypadku zmienne w obiektach będą referencjami, podobnie jak wszystkie zmienne. W związku z tym będziemy zmuszeni mówić o przekazywaniu „referencji według wartości” i musimy używać powiązanych lokalizacji.
źródło
Należy zauważyć, że nie trzeba nawet używać metody „zamień”, aby zmienić pierwotną wartość wartości. Jeśli przypiszesz jedną z wartości skrótu do skrótu, zmienisz oryginalną wartość.
źródło
Wszelkie aktualizacje w tym samym obiekcie nie będą zawierać odniesień do nowej pamięci, ponieważ nadal znajduje się ona w tej samej pamięci. Oto kilka przykładów:
źródło
Tak ale ....
Ruby przekazuje odwołanie do obiektu, a ponieważ wszystko w Rubim jest obiektem, można powiedzieć, że przekazuje je przez odwołanie.
Nie zgadzam się z zamieszczonymi tutaj postami, które twierdzą, że przekazuje wartość, co wydaje mi się pedantycznymi, sympatycznymi grami.
Jednak w efekcie „ukrywa” to zachowanie, ponieważ większość operacji ruby zapewnia „po wyjęciu z pudełka” - na przykład operacje łańcuchowe tworzą kopię obiektu:
Oznacza to, że przez większość czasu oryginalny obiekt pozostaje niezmieniony, co sprawia, że rubin jest „przekazywany przez wartość”.
Oczywiście przy projektowaniu własnych klas zrozumienie szczegółów tego zachowania jest ważne zarówno dla zachowania funkcjonalnego, wydajności pamięci, jak i wydajności.
źródło