Est Ruby passer par référence ou par valeur?
@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
objet ajoute les erreurs à la lang_errors
variable dans le update_lanugages
méthode.
lorsque j'effectue une sauvegarde sur le @user
objet que je perds les erreurs qui ont été initialement stockées dans le lang_errors
variable.
Si ce que je cherche à faire serait de plus d'un hack (ce qui ne semble pas fonctionner). J'aimerais comprendre pourquoi les valeurs de la variable sont délavées. Je comprends passage par référence, donc je voudrais savoir comment la valeur peut être tenu dans cette variable sans être lavé.
- Je remarque aussi que je suis en mesure de conserver cette valeur dans un objet cloné
- Vous devriez regarder Abe Voelker réponse. Mais après avoir exécuté autour du bloc sur ce, voici comment je dirais ça. lorsque vous transmettez un objet Foo à une procédure, une copie de la référence à l'objet est passé, un bar, un Passage par valeur. vous ne pouvez pas modifier l'objet qui les Foo points, mais vous pouvez modifier le contenu de l'objet vers lequel il pointe. Donc, si vous passez un tableau, le contenu du tableau peut être modifié, mais vous ne pouvez pas modifier ce tableau est d'être référencé. agréable d'être en mesure d'utiliser les méthodes de Foo sans avoir à vous soucier de gâcher autres dépendances sur Foo.
Vous devez vous connecter pour publier un commentaire.
Dans la terminologie traditionnelle, Ruby est strictement passer-par-valeur. Mais ce n'est pas vraiment ce que vous demandez ici.
Ruby n'ont pas de notion de un pur, non-valeur de référence, alors vous avez certainement ne pouvez pas passer à une méthode. Les Variables sont toujours des références à des objets. Afin d'obtenir un objet qui ne change pas de sous, vous devez vous dup ou clone de l'objet que vous êtes passé, et donc de donner un objet que personne d'autre n'a une référence à l'. (Même ce n'est pas l'épreuve des balles, même si — à la fois de la norme méthodes de clonage faire une copie superficielle, de sorte que les variables d'instance de la clone pointent toujours vers les mêmes objets que les originaux n'avaient. Si les objets référencés par le ivars muter, ce sera toujours apparaître dans la copie, puisque c'est de référencement sur les mêmes objets.)
bycopy
modificateur de type qui raconte l'exécution pour faire une copie de derrière les coulisses. Qui ne semblent utiles.def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.foo
's variablebar
est une variable indépendante qui n'a tout simplement la même valeur que l'appelantbaz
. Il se trouve que dans ce cas, la valeur est une référence d'objet. Mais en termes de la convention d'appel, il est passé par valeur.ref
mot-clé:RefMeBaby( ref addressOfBob );
. À l'aide deref
est extrêmement rare.L'autre answerers sont tout à fait correct, mais un ami m'a demandé de l'expliquer à lui et de ce que cela se résume à la façon dont Ruby traite des variables, alors j'ai pensé que je voudrais partager quelques photos /explications que j'ai écrit pour lui (mes excuses pour la longueur et probablement un peu de simplification):
Q1: Qu'advient-il lorsque vous affectez une nouvelle variable
str
à une valeur de'foo'
?Un: Un label "
str
est créé que des points à l'objet'foo'
, qui, pour l'état de cet interpréteur Ruby arrive à être à l'emplacement de la mémoire2000
.Q2: Qu'advient-il lorsque vous affectez à la variable existante
str
à un nouvel objet à l'aide de=
?Un: L'étiquette
str
maintenant pointe vers un objet différent.Q3: Qu'advient-il lorsque vous affectez une nouvelle variable
=
àstr
?Une: Un nouveau label appelé
str2
est créé points à la même objet commestr
.Q4: Qu'advient-il si l'objet référencé par
str
etstr2
est changé?Une: les Deux étiquettes toujours au même objet, mais l'objet en lui-même a muté (son contenu ont été modifiés pour être autre chose).
Comment est-ce lié à la question de départ?
C'est essentiellement le même que ce qui se passe en Q3/Q4; la méthode obtient sa propre copie privée de la variable /étiquette (
str2
) qui est transmis à celle-ci (str
). Il ne peut pas changer l'objet sur lequel l'étiquettestr
points de, mais il peut changer le contenu de l'objet qu'ils ont tous deux référence à contenir autre chose:Ruby est passé par valeur. Toujours. Pas d'exceptions. Pas de fi. Pas de mais.
Voici un programme simple qui illustre ce fait:
Fixnum
s,true
,false
,nil
,Symbol
s,Float
s) vous ne pouvez pas être muté, il est sans danger pour le compilateur/interpréteur de passer de l'objet directement par valeur et non pas le pointeur de la valeur. Mais c'est une optimisation de la performance qui ne modifie pas le comportement observable du programme – toute Ruby programme se comporte exactement identiques si les pointeurs deSymbol
s etFixnum
s ont été passé à la place.baz = 'reference'
n'a pas beaucoup de sens. Un pointeur n'est pas une Chaîne. Si vous avez été la manipulation de la valeur de la référence, vous ne sera en mesure d'affecter à un autre pointeur. Dans ce cas=
n'est pas l'affectation d'un pointeur, c'est à dire que instancier une nouvelle Chaîne et de stocker un pointeur vers la Chaîne debar
. Fondamentalement, l'exemple ci-dessus, nous travaillons avec des pointeurs et utilise ensuite une opération de Chaîne pour le prouver. La Chaîne est passé dans foo par référence. Les pointeurs ne sont pas.bar.gsub!(/value/, 'reference')
dans la méthode. Vous verrez que l'objet extérieur est en effet l'objet d'une mutation. effectivement la seule chose passés par valeur est la référence à l'objet.int
ou unint*
. Juste parce que vous êtes en passant un pointeur ne change pas les conventions d'appel. Vous pouvez imaginer Rubis était comme en C, sauf que toutes les méthodes d'accepter et retourner opaqueobject_t*
pointeur. C'est encore passé par valeur.each do
par exemple ahimmelstoss.github.io/blog/2014/06/11/...!
à lui-même, il aura une!
ajouté.each do
est juste un peu étrange, pour moi comme je l'ai récemment emménagé à Ruby. Donc, on dirait que j'ai pour cloner un objet si je ne veux pas d'incidence sur l'original (ou dans mon cas, où l'original est en "lecture seule") dans uneach do
itération?bar.replace 'reference'
le résultatRuby is pass-by-reference
def foo(bar) bar[0..-1] = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
Ruby utilise le "passage par référence d'objet"
(À l'aide de Python de la terminologie.)
- À-dire Ruby utilise le "passage par valeur" ou de "passage par référence" n'est pas vraiment suffisamment descriptif pour être utile. Je pense que la plupart des gens connaissent ces jours-ci, que la terminologie ("valeur" vs "de référence") vient de C++.
En C++, "passage par valeur" signifie que la fonction reçoit une copie de la variable et toutes les modifications apportées à la copie ne pas modifier l'original. C'est vrai pour les objets trop. Si vous transmettez un objet variable par la valeur de l'objet entier (y compris l'ensemble de ses membres) d'avoir copié et toute modification aux membres de ne pas modifier ces membres sur l'objet d'origine. (C'est différent si vous passez un pointeur en valeur mais Ruby n'a pas de pointeurs de toute façon, autant que je sache.)
De sortie:
En C++, "passage par référence" signifie que la fonction obtient l'accès à la variable d'origine. Il peut affecter un tout nouveau littéral entier et la variable d'origine aura alors qu'une valeur trop.
De sortie:
Ruby utilise le passage par valeur (au sens du C++) si l'argument n'est pas un objet. Mais en Ruby, tout est un objet, alors il n'y a vraiment pas de passage par valeur au sens du C++ en Ruby.
En Ruby, "passer par la référence d'objet" (pour utiliser Python terminologie) est utilisé:
Donc Ruby n'utilise pas de "passage par référence" au sens du C++. Si c'était le cas, l'affectation d'un nouvel objet à une variable à l'intérieur d'une fonction serait la cause de l'ancien objet à l'oubli après la fonction renvoyée.
De sortie:
* C'est pourquoi, en Ruby, si vous voulez modifier un objet à l'intérieur d'une fonction, mais oublier ces changements lorsque la fonction retourne une valeur, vous devez explicitement de faire une copie de l'objet avant de faire des modifications temporaires à la copie.
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}"
. Ce imprime "Ruby est passé par valeur". Mais la variable à l'intérieur defoo
est réaffecté. Sibar
serait un tableau de la réaffectation n'aurait pas d'effetbaz
. Pourquoi?Ruby est passé par valeur dans un sens strict, MAIS les valeurs sont des références.
Ce qui pourrait être appelé "passer de la référence par la valeur". Cet article est la meilleure explication que j'ai lu: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Passer de la référence par la valeur peut brièvement être expliqué comme suit:
Le comportement qui en résulte est en fait une combinaison des définitions classiques de passer par référence et par valeur.
Il y a déjà quelques grandes réponses, mais je veux mettre la définition d'une paire des autorités sur le sujet, mais aussi en espérant que quelqu'un peut expliquer ce qu'a indiqué que les autorités Matz (le créateur de Ruby) et David Flanagan signifiait dans leur excellent O'Reilly livre, Le Langage de Programmation Ruby.
Tout cela fait sens pour moi jusqu'à ce que le dernier paragraphe, et surtout cette dernière phrase. C'est, au mieux, trompeuses, et au pire de la confusion. Comment, en quelque sorte, pourrait modifications qui sont passés par valeur de référence de changement de l'objet sous-jacent?
Ruby est passé par référence. Toujours. Pas d'exceptions. Pas de fi. Pas de mais.
Voici un programme simple qui illustre ce fait:
bar
méthode. Vous êtes tout simplement la modification de l'objet de la référence points, mais pas la référence elle-même. La seule manière de modifier les références en Ruby, c'est par cession. Vous ne pouvez pas modifier les références en appelant les méthodes de Ruby parce que les méthodes ne peut être appelé que sur les objets et les références ne sont pas des objets en Ruby. Votre exemple de code montre que Ruby a partagé mutable état (ce qui n'est pas en discussion ici), il n'a cependant rien à éclairer la distinction entre passé par valeur et par référence.Paramètres sont une copie de la référence d'origine. Donc, vous pouvez modifier les valeurs, mais ne peut pas modifier la référence d'origine.
Ruby est interprété. Les Variables sont des références à des données, mais pas les données. Cela facilite l'utilisation de la même variable pour les données de différents types.
Cession de lhs = rhs puis copie la référence sur les rhs, pas les données. Ce qui diffère dans d'autres langages, comme le C, où l'affectation n'est qu'une copie des données à gauche de rhs.
Donc pour l'appel de la fonction, la variable passée, disons x, est en effet copiée dans une variable locale à la fonction, mais x est une référence. Il y aura ensuite deux copies de la référence, à la fois de référencement sur les mêmes données. On va être dans l'appelant, l'une dans la fonction.
Affectation dans la fonction copie puis une nouvelle référence à la fonction de la version de x. Après cela, l'appelant version de x reste inchangé. Il est encore une référence pour les données d'origine.
En revanche, en utilisant le .remplacement de la méthode sur x sera la cause de ruby pour faire une copie de données. Si le remplacement est utilisé avant tout de nouvelles missions, en effet, l'appelant va voir la modification de données dans sa version aussi.
De la même façon, aussi longtemps que la référence d'origine est intact pour le passé dans de variables, les variables d'instance sera le même que le visiteur voit. Dans le cadre d'un objet, les variables d'instance de toujours avoir le plus à jour des valeurs de référence, que ceux-ci sont fournies par l'appelant ou d'un ensemble dans la fonction de la classe a été transmise à.
L'appel par valeur " ou "appel par la référence" est confuse ici en raison de la confusion sur '=' Dans les langages compilés '=' est une copie des données. Ici, dans ce langage interprété '=' est un exemplaire de référence. Dans l'exemple que vous avez la référence transmise dans suivie par un exemplaire de référence si '=' que clobbers l'original passé en référence, et puis les gens en parler comme si '=' étaient une copie des données.
Pour être cohérent avec les définitions que l'on doit garder avec".remplacer", comme c'est une copie des données. Du point de vue de".remplacer", nous voyons que c'est, en effet, passer par référence. En outre, si nous marchons à travers dans le débogueur, nous voyons des références soit passé, que les variables sont des références.
Toutefois, si l'on doit garder '=' comme un cadre de référence, puis nous avons en effet la chance de voir le passé dans les données que jusqu'à une cession, et puis nous n'avons pas plus le voir après la cession, tout en l'appelant de données reste inchangé. Au niveau comportemental c'est le passage par valeur, tant que nous ne la considérons pas comme le passé dans la valeur composite - qu'on ne sera pas en mesure de garder une partie de lui, tandis que l'évolution de l'autre partie, en une seule commande (ainsi que les modifications d'attributions de la référence et de l'original est hors de portée). Il y aura également une verrue, en l'occurrence des variables dans les objets seront des références, comme le sont toutes les variables. Donc, nous allons être obligés de parler en passant références en valeur " et à l'utilisation des locutions.
Essayez ceci:--
identificateur contient object_id 3 pour objet de valeur 1 et l'identifiant de b contient object_id 5 pour la valeur de l'objet 2.
Maintenant le faire:--
Maintenant, a et b contiennent les même object_id 5 qui se réfère à la valeur de l'objet 2.
Donc, Ruby variable contient object_ids à se référer à des objets de valeur.
Suivant donne également d'erreur:--
mais cela ne donnera pas d'erreur:--
Ici identificateur retourne un objet de valeur 11 objet dont l'id est de 23 c'est à dire object_id 23 est à un identificateur, nous voyons Maintenant un exemple en utilisant la méthode.
arg foo est affecté avec la valeur de retour de x.
Il montre clairement que l'argument est passé par valeur 11, et la valeur 11 étant lui-même un objet a objet unique id 23.
Maintenant voir aussi ceci:--
Ici, identifiant arg première contient object_id 23 référer 11 et après affectation interne avec l'objet de valeur 12, il contient object_id 25. Mais il ne change pas la valeur référencée par l'identificateur x utilisés dans la méthode appelante.
Par conséquent, le Rubis est le passage par valeur et Ruby variables ne contiennent pas de valeurs, mais ne contiennent référence à la valeur de l'objet.
Il convient de noter que vous n'avez pas à même d'utiliser la fonction "remplacer" la méthode pour modifier la valeur d'origine de la valeur. Si vous affectez une des valeurs de hachage pour une table de hachage, vous modifiez la valeur d'origine.
Des mises à jour de l'objet même de ne pas rendre les références à nouveau de la mémoire, car il est toujours dans la même mémoire.
Voici quelques exemples :