@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
Objekt fügt der lang_errors
Variablen in der update_lanugages
Methode Fehler hinzu . Wenn ich das @user
Objekt speichere, verliere ich die Fehler, die ursprünglich in der lang_errors
Variablen gespeichert waren .
Aber was ich versuche zu tun, wäre eher ein Hack (der nicht zu funktionieren scheint). Ich würde gerne verstehen, warum die variablen Werte verwaschen werden. Ich verstehe Pass by Reference und möchte wissen, wie der Wert in dieser Variablen gehalten werden kann, ohne verwaschen zu werden.
Antworten:
In der traditionellen Terminologie ist Ruby streng pass-by-value . Aber das ist nicht wirklich das, was Sie hier fragen.
Ruby hat kein Konzept für einen reinen Wert ohne Referenz, daher können Sie keinen Wert an eine Methode übergeben. Variablen sind immer Verweise auf Objekte. Um ein Objekt zu erhalten, das sich unter Ihnen nicht ändert, müssen Sie das übergebene Objekt dupen oder klonen und so ein Objekt angeben, auf das niemand sonst verweist. (Auch dies ist nicht kugelsicher - beide Standardklonmethoden führen eine flache Kopie durch, sodass die Instanzvariablen des Klons immer noch auf dieselben Objekte verweisen wie die Originale. Wenn die Objekte, auf die die Ivars verweisen, mutieren, wird dies mutieren wird immer noch in der Kopie angezeigt, da sie auf dieselben Objekte verweist.)
quelle
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.Die anderen Antwortenden sind alle korrekt, aber ein Freund hat mich gebeten, ihm dies zu erklären, und es läuft wirklich darauf hinaus, wie Ruby mit Variablen umgeht. Deshalb dachte ich, ich würde einige einfache Bilder / Erklärungen teilen, die ich für ihn geschrieben habe (Entschuldigung für die Länge und wahrscheinlich eine gewisse Vereinfachung):
Q1: Was passiert, wenn Sie
str
einem Wert von eine neue Variable zuweisen'foo'
?A: Es wird eine Bezeichnung mit dem Namen
str
erstellt, die auf das Objekt zeigt'foo'
, das sich für den Status dieses Ruby-Interpreters zufällig im Speicher befindet2000
.F2: Was passiert, wenn Sie die vorhandene Variable
str
mit einem neuen Objekt zuweisen=
?A: Die Beschriftung zeigt
str
jetzt auf ein anderes Objekt.Q3: Was passiert , wenn Sie eine neue Variable zuweisen
=
zustr
?A: Es wird eine neue Bezeichnung mit dem Namen
str2
erstellt, die auf dasselbe Objekt wie zeigtstr
.Q4: Was passiert , wenn das Objekt referenziert durch
str
undstr2
wird geändert?A: Beide Beschriftungen zeigen immer noch auf dasselbe Objekt, aber dieses Objekt selbst ist mutiert (sein Inhalt hat sich geändert, um etwas anderes zu sein).
In welcher Beziehung steht dies zur ursprünglichen Frage?
Es ist im Grunde dasselbe wie in Q3 / Q4. Die Methode erhält eine eigene private Kopie der Variablen / label (
str2
), die an sie übergeben wird (str
). Es kann nicht geändert werden, auf welches Objekt die Beschriftungstr
verweist , aber es kann den Inhalt des Objekts ändern, auf das beide verweisen, um Folgendes zu enthalten:quelle
Ruby verwendet "Objektreferenz übergeben"
(Verwenden der Python-Terminologie.)
Zu sagen, dass Ruby "Wert übergeben" oder "Referenz übergeben" verwendet, ist nicht beschreibend genug, um hilfreich zu sein. Ich denke, wie die meisten Leute heutzutage wissen, stammt diese Terminologie ("Wert" vs "Referenz") aus C ++.
In C ++ bedeutet "Wert übergeben", dass die Funktion eine Kopie der Variablen erhält und Änderungen an der Kopie das Original nicht ändern. Das gilt auch für Objekte. Wenn Sie eine Objektvariable als Wert übergeben, wird das gesamte Objekt (einschließlich aller seiner Mitglieder) kopiert, und Änderungen an den Mitgliedern ändern diese Mitglieder des ursprünglichen Objekts nicht. (Es ist anders, wenn Sie einen Zeiger als Wert übergeben, aber Ruby hat sowieso keine Zeiger, AFAIK.)
Ausgabe:
In C ++ bedeutet "Referenzübergabe", dass die Funktion Zugriff auf die ursprüngliche Variable erhält. Es kann eine ganz neue Literal-Ganzzahl zuweisen, und die ursprüngliche Variable hat dann auch diesen Wert.
Ausgabe:
Ruby verwendet den Pass-by-Wert (im C ++ - Sinne), wenn das Argument kein Objekt ist. Aber in Ruby ist alles ein Objekt, so dass es in Ruby wirklich keinen Wertübergang im C ++ - Sinne gibt.
In Ruby wird "Objektreferenz übergeben" (um die Terminologie von Python zu verwenden) verwendet:
Daher verwendet Ruby kein "Pass by Reference" im C ++ - Sinne. Wenn dies der Fall wäre, würde das Zuweisen eines neuen Objekts zu einer Variablen innerhalb einer Funktion dazu führen, dass das alte Objekt nach der Rückgabe der Funktion vergessen wird.
Ausgabe:
* Wenn Sie in Ruby ein Objekt innerhalb einer Funktion ändern möchten, diese Änderungen jedoch bei der Rückkehr der Funktion vergessen möchten, müssen Sie explizit eine Kopie des Objekts erstellen, bevor Sie Ihre temporären Änderungen an der Kopie vornehmen.
quelle
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}"
. Dies gibt "Ruby is pass-by-value" aus. Die Variable im Innerenfoo
wird jedoch neu zugewiesen. Wennbar
es sich um ein Array handeln würde, würde sich die Neuzuweisung nicht auswirkenbaz
. Warum?Ruby ist ein Pass-by-Wert. Immer. Keine Ausnahmen. Kein Wenn. Kein Aber.
Hier ist ein einfaches Programm, das diese Tatsache demonstriert:
quelle
Ruby ist im engeren Sinne ein Pass-by-Wert, ABER die Werte sind Referenzen.
Dies könnte als " Pass-Reference-by-Value " bezeichnet werden. Dieser Artikel hat die beste Erklärung, die ich gelesen habe: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Pass-Reference-by-Value könnte kurz wie folgt erklärt werden:
Das resultierende Verhalten ist tatsächlich eine Kombination der klassischen Definitionen von Referenzübergabe und Wertübergabe.
quelle
Es gibt bereits einige gute Antworten, aber ich möchte die Definition eines Paares von Autoritäten zu diesem Thema veröffentlichen, aber auch hoffen, dass jemand erklären könnte, was die Autoritäten Matz (Schöpfer von Ruby) und David Flanagan in ihrem ausgezeichneten O'Reilly-Buch gemeint haben. Die Ruby-Programmiersprache .
Dies alles macht für mich bis zu diesem letzten Absatz und insbesondere bis zu diesem letzten Satz Sinn . Dies ist bestenfalls irreführend und schlimmer noch verwirrend. Wie können Änderungen an dieser Referenz für übergebene Werte das zugrunde liegende Objekt in irgendeiner Weise ändern?
quelle
Ruby ist eine Referenz. Immer. Keine Ausnahmen. Kein Wenn. Kein Aber.
Hier ist ein einfaches Programm, das diese Tatsache demonstriert:
quelle
bar
Methode. Sie ändern lediglich das Objekt, auf das die Referenz verweist , nicht jedoch die Referenz selbst. Sie können Referenzen in Ruby nur durch Zuweisung ändern. Sie können Referenzen nicht ändern, indem Sie Methoden in Ruby aufrufen, da Methoden nur für Objekte aufgerufen werden können und Referenzen keine Objekte in Ruby sind. Ihr Codebeispiel zeigt, dass Ruby einen veränderlichen Status hat (der hier nicht diskutiert wird), jedoch nichts, um die Unterscheidung zwischen Pass-by-Value und Pass-by-Reference zu beleuchten.Parameter sind eine Kopie der Originalreferenz. Sie können also Werte ändern, aber nicht die ursprüngliche Referenz.
quelle
Versuche dies:--
Bezeichner a enthält Objekt_ID 3 für Wertobjekt 1 und Bezeichner b enthält Objekt_ID 5 für Wertobjekt 2.
Mach das jetzt:--
Jetzt enthalten a und b beide dieselbe object_id 5, die sich auf das Wertobjekt 2 bezieht. Die Ruby-Variable enthält also object_ids, um auf Wertobjekte zu verweisen.
Wenn Sie Folgendes tun, wird auch ein Fehler angezeigt: -
Dies führt jedoch nicht zu einem Fehler: -
Hier gibt der Bezeichner a ein Wertobjekt 11 zurück, dessen Objekt-ID 23 ist, dh die Objekt-ID 23 befindet sich am Bezeichner a. Nun sehen wir ein Beispiel unter Verwendung der Methode.
arg in foo wird mit dem Rückgabewert x zugewiesen. Es zeigt deutlich, dass das Argument vom Wert 11 übergeben wird und der Wert 11, der selbst ein Objekt ist, eine eindeutige Objekt-ID 23 hat.
Nun sehen Sie dies auch: -
Hier enthält der Bezeichner arg zuerst object_id 23, um auf 11 zu verweisen, und nach der internen Zuweisung mit dem Wert object 12 enthält er object_id 25. Der Wert, auf den durch den in der aufrufenden Methode verwendeten Bezeichner x verwiesen wird, wird jedoch nicht geändert.
Daher wird Ruby als Wert übergeben, und Ruby-Variablen enthalten keine Werte, sondern Verweise auf Wertobjekte.
quelle
Ruby wird interpretiert. Variablen sind Verweise auf Daten, jedoch nicht auf die Daten selbst. Dies erleichtert die Verwendung derselben Variablen für Daten unterschiedlicher Typen.
Die Zuweisung von lhs = rhs kopiert dann die Referenz auf die rhs, nicht die Daten. Dies unterscheidet sich in anderen Sprachen, wie z. B. C, wo die Zuweisung eine Datenkopie von rhs nach lhs durchführt.
Für den Funktionsaufruf wird die übergebene Variable, z. B. x, zwar in eine lokale Variable in der Funktion kopiert, aber x ist eine Referenz. Es gibt dann zwei Kopien der Referenz, die beide auf dieselben Daten verweisen. Einer wird im Anrufer sein, einer in der Funktion.
Die Zuweisung in der Funktion würde dann einen neuen Verweis auf die Funktionsversion von x kopieren. Danach bleibt die Aufruferversion von x unverändert. Es ist immer noch ein Verweis auf die Originaldaten.
Im Gegensatz dazu führt die Verwendung der .replace-Methode für x dazu, dass Ruby eine Datenkopie erstellt. Wenn Ersetzen vor neuen Zuweisungen verwendet wird, sieht der Anrufer die Datenänderung auch in seiner Version.
In ähnlicher Weise sind die Instanzvariablen dieselben, die der Aufrufer sieht, solange die ursprüngliche Referenz für die übergebene Variable gültig ist. Im Rahmen eines Objekts haben die Instanzvariablen immer die aktuellsten Referenzwerte, unabhängig davon, ob diese vom Aufrufer bereitgestellt oder in der Funktion festgelegt wurden, an die die Klasse übergeben wurde.
Der 'Aufruf nach Wert' oder 'Aufruf nach Referenz' ist hier aufgrund der Verwirrung über '=' In kompilierten Sprachen '=' ist eine Datenkopie durcheinander. Hier in dieser interpretierten Sprache ist '=' eine Referenzkopie. In dem Beispiel haben Sie die Referenz übergeben, gefolgt von einer Referenzkopie durch '=', die das als Referenz übergebene Original blockiert, und dann wird darüber gesprochen, als wäre '=' eine Datenkopie.
Um mit den Definitionen übereinzustimmen, müssen wir '.replace' beibehalten, da es sich um eine Datenkopie handelt. Aus der Perspektive von '.replace' sehen wir, dass dies tatsächlich als Referenz gilt. Wenn wir im Debugger durchgehen, sehen wir außerdem, dass Referenzen übergeben werden, da Variablen Referenzen sind.
Wenn wir jedoch '=' als Referenzrahmen beibehalten müssen, können wir die übergebenen Daten tatsächlich bis zu einer Zuweisung sehen, und dann können wir sie nach der Zuweisung nicht mehr sehen, während die Daten des Anrufers unverändert bleiben. Auf Verhaltensebene wird dies als Wert übergeben, solange wir den übergebenen Wert nicht als zusammengesetzt betrachten, da wir nicht in der Lage sind, einen Teil davon beizubehalten, während wir den anderen Teil in einer einzelnen Zuweisung ändern (wie diese Zuweisung) ändert die Referenz und das Original verlässt den Geltungsbereich). Es wird auch eine Warze geben, in diesem Fall sind Variablen in Objekten Referenzen, ebenso wie alle Variablen. Daher werden wir gezwungen sein, über das Übergeben von 'Referenzen nach Wert' zu sprechen und verwandte Positionen zu verwenden.
quelle
Es ist zu beachten, dass Sie nicht einmal die "Ersetzen" -Methode verwenden müssen, um den ursprünglichen Wert des Werts zu ändern. Wenn Sie einen Hashwert für einen Hash zuweisen, ändern Sie den ursprünglichen Wert.
quelle
Bei Aktualisierungen im selben Objekt wird nicht auf den neuen Speicher verwiesen, da sich dieser noch im selben Speicher befindet. Hier einige Beispiele:
quelle
Ja aber ....
Ruby übergibt einen Verweis auf ein Objekt, und da alles in Ruby ein Objekt ist, kann man sagen, dass es als Verweis übergeben wird.
Ich bin nicht mit den Postings hier einverstanden, in denen behauptet wird, dass es sich um einen Wert handelt, der mir wie pedantische, symantische Spiele erscheint.
Tatsächlich "verbirgt" es jedoch das Verhalten, da die meisten Operationen, die Ruby "out of the box" bereitstellt - beispielsweise Zeichenfolgenoperationen, eine Kopie des Objekts erstellen:
Dies bedeutet, dass das ursprüngliche Objekt die meiste Zeit unverändert bleibt, was den Anschein erweckt, dass Ruby "Wert übergeben" ist.
Natürlich ist beim Entwerfen eigener Klassen ein Verständnis der Details dieses Verhaltens sowohl für das Funktionsverhalten als auch für die Speichereffizienz und die Leistung wichtig.
quelle