@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
L'objet ajoute des erreurs à la lang_errors
variable dans la update_lanugages
méthode. lorsque j'effectue une sauvegarde sur l' @user
objet, je perds les erreurs qui étaient initialement stockées dans la lang_errors
variable.
Bien que ce que j'essaie de faire serait plus un hack (qui ne semble pas fonctionner). Je voudrais comprendre pourquoi les valeurs variables sont effacées. Je comprends passer par référence, donc je voudrais savoir comment la valeur peut être conservée dans cette variable sans être effacée.
Réponses:
Dans la terminologie traditionnelle, Ruby est strictement pass-by-value . Mais ce n'est pas vraiment ce que vous demandez ici.
Ruby n'a aucun concept de valeur pure et non référence, vous ne pouvez donc certainement pas en transmettre une à une méthode. Les variables sont toujours des références à des objets. Afin d'obtenir un objet qui ne changera pas sous vous, vous devez dupliquer ou cloner l'objet que vous avez passé, donnant ainsi un objet auquel personne d'autre n'a de référence. (Même cela n'est pas à l'épreuve des balles, cependant - les deux méthodes de clonage standard effectuent une copie superficielle, de sorte que les variables d'instance du clone pointent toujours vers les mêmes objets que les originaux. Si les objets référencés par les ivars mutent, cela apparaissent toujours dans la copie, car elle fait référence aux mêmes objets.)
la source
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.Les autres répondeurs ont tous raison, mais un ami m'a demandé de lui expliquer cela et ce que cela signifie vraiment, c'est comment Ruby gère les variables, alors j'ai pensé partager quelques images / explications simples que j'ai écrites pour lui (excuses pour la longueur et probablement une simplification excessive):
Q1: Que se passe-t-il lorsque vous affectez une nouvelle variable
str
à une valeur de'foo'
?R: Une étiquette appelée
str
est créée qui pointe vers l'objet'foo'
qui, pour l'état de cet interpréteur Ruby, se trouve être à l'emplacement de la mémoire2000
.Q2: Que se passe-t-il lorsque vous affectez la variable existante
str
à un nouvel objet à l'aide de=
?R: L'étiquette
str
pointe désormais vers un autre objet.Q3: Que se passe-t-il lorsque vous affectez une nouvelle variable
=
àstr
?R: Une nouvelle étiquette appelée
str2
est créée et pointe vers le même objet questr
.Q4: Que se passe-t-il si l'objet référencé par
str
etstr2
est modifié?R: Les deux étiquettes pointent toujours vers le même objet, mais cet objet lui-même a muté (son contenu a changé pour être autre chose).
Quel est le rapport avec la question d'origine?
C'est fondamentalement la même chose que ce qui se passe dans Q3 / Q4; la méthode obtient sa propre copie privée de la variable / label (
str2
) qui lui est transmise (str
). Il ne peut pas changer vers quel objet l'étiquettestr
pointe , mais il peut changer le contenu de l'objet qu'ils référencent tous les deux pour contenir d'autre:la source
Ruby utilise "passer par référence d'objet"
(Utilisation de la terminologie de Python.)
Dire que Ruby utilise "passer par valeur" ou "passer par référence" n'est pas vraiment assez descriptif pour être utile. Je pense que comme la plupart des gens le savent de nos jours, cette terminologie ("valeur" vs "référence") vient de C ++.
En C ++, "passer par valeur" signifie que la fonction obtient une copie de la variable et que toute modification apportée à la copie ne change pas l'original. C'est vrai aussi pour les objets. Si vous transmettez une variable d'objet par valeur, l'objet entier (y compris tous ses membres) est copié et les modifications apportées aux membres ne modifient pas ces membres sur l'objet d'origine. (C'est différent si vous passez un pointeur par valeur mais Ruby n'a pas de pointeurs de toute façon, AFAIK.)
Production:
En C ++, "passer par référence" signifie que la fonction a accès à la variable d'origine. Il peut affecter un tout nouvel entier littéral et la variable d'origine aura alors également cette valeur.
Production:
Ruby utilise le passage par valeur (au sens C ++) si l'argument n'est pas un objet. Mais dans Ruby, tout est un objet, donc il n'y a vraiment pas de valeur de passage au sens C ++ dans Ruby.
Dans Ruby, "passer par référence d'objet" (pour utiliser la terminologie de Python) est utilisé:
Par conséquent, Ruby n'utilise pas "passe par référence" dans le sens C ++. Si tel était le cas, l'attribution d'un nouvel objet à une variable à l'intérieur d'une fonction entraînerait l'oubli de l'ancien objet après le retour de la fonction.
Production:
* C'est pourquoi, dans Ruby, si vous souhaitez modifier un objet à l'intérieur d'une fonction mais oublier ces changements lorsque la fonction revient, alors vous devez explicitement faire une copie de l'objet avant d'apporter vos modifications temporaires à la copie.
la source
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}"
. Cela affiche "Ruby est une valeur de passage". Mais la variable à l'intérieurfoo
est réaffectée. S'ilbar
s'agissait d'un tableau, la réaffectation n'aurait aucun effetbaz
. Pourquoi?Ruby est une valeur de passage. Toujours. Aucune exception. Pas de si. Pas de mais.
Voici un programme simple qui démontre ce fait:
la source
Ruby est une valeur de passage au sens strict, MAIS les valeurs sont des références.
Cela pourrait être appelé " pass-reference-by-value ". Cet article a la meilleure explication que j'ai lue: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Pass-reference-by-value pourrait être brièvement expliqué comme suit:
Le comportement qui en résulte est en fait une combinaison des définitions classiques de passe-par-référence et de passe-par-valeur.
la source
Il y a déjà de bonnes réponses, mais je veux publier la définition d'une paire d'autorités sur le sujet, mais j'espère aussi que quelqu'un pourrait expliquer ce que les autorités Matz (créateur de Ruby) et David Flanagan ont voulu dire dans leur excellent livre O'Reilly, Le langage de programmation Ruby .
Tout cela a du sens pour moi jusqu'au dernier paragraphe, et surtout cette dernière phrase. C'est au mieux trompeur et au pire confondant. Comment, de quelque manière que ce soit, des modifications à cette référence transmise par valeur peuvent-elles changer l'objet sous-jacent?
la source
Ruby est passe-par-référence. Toujours. Aucune exception. Pas de si. Pas de mais.
Voici un programme simple qui démontre ce fait:
la source
bar
méthode. Vous modifiez simplement l'objet vers lequel la référence pointe , mais pas la référence elle-même. Ils ne peuvent modifier les références dans Ruby que par affectation. Vous ne pouvez pas modifier des références en appelant des méthodes dans Ruby car les méthodes ne peuvent être appelées que sur des objets et les références ne sont pas des objets dans Ruby. Votre exemple de code montre que Ruby a partagé un état mutable (ce qui n'est pas discuté ici), il ne fait cependant rien pour éclairer la distinction entre pass-by-value et pass-by-reference.Les paramètres sont une copie de la référence d'origine. Vous pouvez donc modifier les valeurs, mais pas la référence d'origine.
la source
Essaye ça:--
l'identifiant a contient id_objet 3 pour l'objet valeur 1 et l'identifiant b contient l'id_objet 5 pour l'objet valeur 2.
Maintenant, faites ceci: -
Maintenant, a et b contiennent tous deux le même object_id 5 qui fait référence à l'objet de valeur 2. Ainsi, la variable Ruby contient object_ids pour faire référence aux objets de valeur.
Faire ce qui suit donne également une erreur: -
mais cela ne donnera pas d'erreur: -
Ici, l'identifiant a renvoie la valeur de l'objet 11 dont l'ID d'objet est 23, c'est-à-dire que object_id 23 est à l'identificateur a. Maintenant, nous voyons un exemple en utilisant la méthode.
arg dans foo est affecté avec une valeur de retour de x. Il montre clairement que l'argument est passé par la valeur 11, et la valeur 11 étant lui-même un objet a un identifiant d'objet unique 23.
Maintenant, voyez cela aussi: -
Ici, l'identifiant arg contient d'abord object_id 23 pour faire référence à 11 et après affectation interne avec la valeur objet 12, il contient object_id 25. Mais il ne change pas la valeur référencée par l'identifiant x utilisé dans la méthode d'appel.
Par conséquent, Ruby est passé par valeur et les variables Ruby ne contiennent pas de valeurs mais contiennent une référence à l'objet valeur.
la source
Ruby est interprété. Les variables sont des références aux données, mais pas aux données elles-mêmes. Cela facilite l'utilisation de la même variable pour des données de types différents.
L'affectation de lhs = rhs copie alors la référence sur les rhs, pas les données. Cela diffère dans d'autres langages, tels que C, où l'affectation effectue une copie des données vers lhs à partir de rhs.
Donc, pour l'appel de fonction, la variable passée, disons x, est en effet copiée dans une variable locale dans la fonction, mais x est une référence. Il y aura alors deux copies de la référence, toutes deux faisant référence aux mêmes données. Un sera dans l'appelant, un dans la fonction.
L'affectation dans la fonction copiera alors une nouvelle référence à la version de x de la fonction. Après cela, la version de x de l'appelant reste inchangée. C'est toujours une référence aux données originales.
En revanche, en utilisant la méthode .replace sur x, Ruby effectuera une copie des données. Si replace est utilisé avant toute nouvelle affectation, alors l'appelant verra également les données changer dans sa version.
De même, tant que la référence d'origine est intacte pour la variable passée, les variables d'instance seront les mêmes que celles que l'appelant voit. Dans le cadre d'un objet, les variables d'instance ont toujours les valeurs de référence les plus à jour, qu'elles soient fournies par l'appelant ou définies dans la fonction à laquelle la classe a été transmise.
L'appel par valeur ou l'appel par référence est embrouillé ici à cause de la confusion sur '=' Dans les langues compilées '=' est une copie de données. Voici dans ce langage interprété '=' est une copie de référence. Dans l'exemple, vous avez transmis la référence suivie d'une copie de référence si '=' qui détruit l'original passé en référence, puis les gens qui en parlent comme si '=' étaient une copie de données.
Pour être cohérent avec les définitions, nous devons conserver «.replace» car il s'agit d'une copie de données. Du point de vue de «.replace», nous voyons que cela est effectivement passé par référence. De plus, si nous parcourons le débogueur, nous voyons des références transmises, car les variables sont des références.
Cependant, si nous devons conserver '=' comme cadre de référence, alors nous pouvons effectivement voir les données transmises jusqu'à une affectation, puis nous ne pouvons plus le voir après l'affectation alors que les données de l'appelant restent inchangées. Au niveau comportemental, il s'agit d'une valeur de passage tant que nous ne considérons pas la valeur transmise comme composite - car nous ne pourrons pas en conserver une partie tout en modifiant l'autre partie dans une seule affectation (comme cette affectation modifie la référence et l'original sort du cadre). Il y aura également une verrue, dans ce cas, les variables dans les objets seront des références, comme toutes les variables. Par conséquent, nous serons obligés de parler de passer des «références par valeur» et d'utiliser des locutions connexes.
la source
Il convient de noter que vous n'avez même pas besoin d'utiliser la méthode "replace" pour modifier la valeur d'origine. Si vous affectez l'une des valeurs de hachage à un hachage, vous modifiez la valeur d'origine.
la source
Toute mise à jour dans le même objet ne fera pas les références à la nouvelle mémoire car elle est toujours dans la même mémoire. Voici quelques exemples:
la source
Oui mais ....
Ruby transmet une référence à un objet et puisque tout dans ruby est un objet, vous pouvez dire qu'il est transmis par référence.
Je ne suis pas d'accord avec les publications ici prétendant que c'est une valeur de passage, cela me semble être des jeux pédants et symétriques.
Cependant, en effet, il "cache" le comportement car la plupart des opérations ruby fournit "prêt à l'emploi" - par exemple, les opérations de chaîne, produisent une copie de l'objet:
Cela signifie que la plupart du temps, l'objet d'origine reste inchangé donnant l'apparence que le rubis est "passer par la valeur".
Bien sûr, lors de la conception de vos propres classes, une compréhension des détails de ce comportement est importante pour le comportement fonctionnel, l'efficacité de la mémoire et les performances.
la source