@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
El objeto agrega errores a la lang_errors
variable en el update_lanugages
método. cuando guardo el @user
objeto pierdo los errores que se almacenaron inicialmente en la lang_errors
variable.
Aunque lo que intento hacer sería más un truco (que no parece estar funcionando). Me gustaría entender por qué se borran los valores de las variables. Entiendo pasar por referencia, así que me gustaría saber cómo se puede mantener el valor en esa variable sin ser eliminado.
Respuestas:
En la terminología tradicional, Ruby es estrictamente paso por valor . Pero eso no es realmente lo que estás preguntando aquí.
Ruby no tiene ningún concepto de valor puro, sin referencia, por lo que ciertamente no puede pasar uno a un método. Las variables son siempre referencias a objetos. Para obtener un objeto que no cambie debajo de usted, debe duplicar o clonar el objeto que le pasó, dando así un objeto al que nadie más tiene referencia. (Aunque esto no es a prueba de balas, ambos métodos de clonación estándar hacen una copia superficial, por lo que las variables de instancia del clon todavía apuntan a los mismos objetos que los originales. Si los objetos a los que hace referencia el ivars mutan, eso todavía aparece en la copia, ya que hace referencia a los mismos objetos).
fuente
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.Las otras respuestas son correctas, pero un amigo me pidió que le explicara esto y lo que realmente se reduce a cómo Ruby maneja las variables, por lo que pensé que compartiría algunas imágenes / explicaciones simples que escribí para él (disculpas por la longitud y probablemente alguna simplificación excesiva):
P1: ¿Qué sucede cuando asigna una nueva variable
str
a un valor de'foo'
?R: Se
str
crea una etiqueta llamada que apunta al objeto'foo'
, que para el estado de este intérprete de Ruby se encuentra en la ubicación de la memoria2000
.P2: ¿Qué sucede cuando asigna la variable existente
str
a un nuevo objeto usando=
?A: La etiqueta
str
ahora apunta a un objeto diferente.P3: ¿Qué sucede cuando asigna una nueva variable
=
astr
?R: Se
str2
crea una nueva etiqueta llamada que apunta al mismo objeto questr
.P4: ¿Qué sucede si el objeto al que hace referencia
str
ystr2
se cambia?R: Ambas etiquetas todavía apuntan al mismo objeto, pero ese objeto en sí mismo ha mutado (su contenido ha cambiado para ser otra cosa).
¿Cómo se relaciona esto con la pregunta original?
Básicamente es lo mismo que sucede en Q3 / Q4; el método obtiene su propia copia privada de la variable / etiqueta (
str2
) que se le pasa (str
). No puede cambiar a qué objetostr
apunta la etiqueta , pero puede cambiar el contenido del objeto al que ambos hacen referencia para contener:fuente
Ruby usa "pasar por referencia de objeto"
(Usando la terminología de Python).
Decir que Ruby usa "pasar por valor" o "pasar por referencia" no es realmente lo suficientemente descriptivo como para ser útil. Creo que, como la mayoría de la gente lo sabe en estos días, esa terminología ("valor" vs "referencia") proviene de C ++.
En C ++, "pasar por valor" significa que la función obtiene una copia de la variable y cualquier cambio en la copia no cambia el original. Eso también es cierto para los objetos. Si pasa una variable de objeto por valor, se copia todo el objeto (incluidos todos sus miembros) y cualquier cambio en los miembros no cambia esos miembros en el objeto original. (Es diferente si pasa un puntero por valor, pero Ruby no tiene punteros de todos modos, AFAIK).
Salida:
En C ++, "pasar por referencia" significa que la función obtiene acceso a la variable original. Puede asignar un entero literal completamente nuevo y la variable original también tendrá ese valor.
Salida:
Ruby usa pasar por valor (en el sentido de C ++) si el argumento no es un objeto. Pero en Ruby todo es un objeto, por lo que realmente no hay un paso por valor en el sentido de C ++ en Ruby.
En Ruby, se usa "pasar por referencia de objeto" (para usar la terminología de Python):
Por lo tanto, Ruby no usa "pasar por referencia" en el sentido de C ++. Si lo hiciera, la asignación de un nuevo objeto a una variable dentro de una función haría que el objeto antiguo se olvidara después de que la función regresara.
Salida:
* Esta es la razón por la cual, en Ruby, si desea modificar un objeto dentro de una función pero olvida esos cambios cuando la función regresa, debe hacer explícitamente una copia del objeto antes de realizar sus cambios temporales en la copia.
fuente
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}"
. Esto imprime "Ruby es paso por valor". Pero la variable dentrofoo
se reasigna. Sibar
fuera una matriz, la reasignación no tendría efectobaz
. ¿Por qué?Ruby es paso por valor. Siempre. Sin excepciones. No si. Sin peros.
Aquí hay un programa simple que demuestra ese hecho:
fuente
Ruby es paso por valor en sentido estricto, PERO los valores son referencias.
Esto podría llamarse " referencia de paso por valor ". Este artículo tiene la mejor explicación que he leído: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
La referencia de paso por valor podría explicarse brevemente de la siguiente manera:
El comportamiento resultante es en realidad una combinación de las definiciones clásicas de paso por referencia y paso por valor.
fuente
Ya hay algunas respuestas excelentes, pero quiero publicar la definición de un par de autoridades sobre el tema, pero también esperando que alguien pueda explicar lo que dijeron las autoridades Matz (creador de Ruby) y David Flanagan en su excelente libro O'Reilly, El lenguaje de programación Ruby .
Todo esto tiene sentido para mí hasta el último párrafo, y especialmente esa última oración. Esto es, en el mejor de los casos, engañoso y, en el peor, confuso. ¿Cómo, de alguna manera, las modificaciones a esa referencia pasada por valor podrían cambiar el objeto subyacente?
fuente
Ruby es paso por referencia. Siempre. Sin excepciones. No si. Sin peros.
Aquí hay un programa simple que demuestra ese hecho:
fuente
bar
método. Simplemente está modificando el objeto al que apunta la referencia , pero no la referencia en sí. La única forma de modificar referencias en Ruby es por asignación. No puede modificar referencias llamando a métodos en Ruby porque los métodos solo se pueden invocar en objetos y las referencias no son objetos en Ruby. Su ejemplo de código demuestra que Ruby ha compartido un estado mutable (que no se está discutiendo aquí), sin embargo, no hace nada para iluminar la distinción entre pasar por valor y pasar por referencia.Los parámetros son una copia de la referencia original. Por lo tanto, puede cambiar los valores, pero no puede cambiar la referencia original.
fuente
Prueba esto:--
el identificador a contiene object_id 3 para el objeto de valor 1 y el identificador b contiene object_id 5 para el objeto de valor 2.
Ahora hacer esto:--
Ahora, a y b contienen el mismo object_id 5 que se refiere al objeto de valor 2. Entonces, la variable Ruby contiene object_ids para referirse a los objetos de valor.
Hacer lo siguiente también da error: -
pero hacer esto no dará error: -
Aquí el identificador a devuelve el objeto de valor 11 cuyo id de objeto es 23, es decir, object_id 23 está en el identificador a, ahora vemos un ejemplo utilizando el método.
arg en foo se asigna con el valor de retorno de x. Muestra claramente que el argumento es pasado por el valor 11, y siendo el valor 11 un objeto en sí mismo, tiene un ID de objeto único 23.
Ahora vea esto también: -
Aquí, el identificador arg primero contiene object_id 23 para referir 11 y después de la asignación interna con el objeto de valor 12, contiene object_id 25. Pero no cambia el valor al que hace referencia el identificador x utilizado en el método de llamada.
Por lo tanto, Ruby es pasar por valor y las variables de Ruby no contienen valores, pero contienen referencias al objeto de valor.
fuente
Ruby es interpretado. Las variables son referencias a datos, pero no los datos en sí. Esto facilita el uso de la misma variable para datos de diferentes tipos.
La asignación de lhs = rhs luego copia la referencia en la rhs, no los datos. Esto difiere en otros lenguajes, como C, donde la asignación hace una copia de datos a lhs de rhs.
Entonces, para la llamada a la función, la variable pasada, digamos x, se copia en una variable local en la función, pero x es una referencia. Luego habrá dos copias de la referencia, ambas haciendo referencia a los mismos datos. Uno estará en la persona que llama, uno en la función.
La asignación en la función luego copiaría una nueva referencia a la versión de la función de x. Después de esto, la versión de x de la persona que llama permanece sin cambios. Sigue siendo una referencia a los datos originales.
Por el contrario, usar el método .replace en x hará que ruby haga una copia de datos. Si se usa el reemplazo antes de cualquier nueva asignación, entonces la persona que llama verá el cambio de datos en su versión también.
Del mismo modo, siempre que la referencia original esté intacta para la variable pasada, las variables de instancia serán las mismas que ve la persona que llama. Dentro del marco de un objeto, las variables de instancia siempre tienen los valores de referencia más actualizados, ya sean proporcionados por el llamador o establecidos en la función a la que se pasó la clase.
La 'llamada por valor' o 'llamada por referencia' se confunde aquí debido a la confusión sobre '=' En idiomas compilados '=' es una copia de datos. Aquí en este lenguaje interpretado '=' hay una copia de referencia. En el ejemplo, se pasa la referencia seguida de una copia de referencia aunque '=' que identifica el original pasado como referencia, y luego las personas que hablan de ello como si '=' fuera una copia de datos.
Para ser coherente con las definiciones, debemos mantener '.replace', ya que es una copia de datos. Desde la perspectiva de '.replace' vemos que esto es realmente pasar por referencia. Además, si pasamos por el depurador, vemos que se pasan referencias, ya que las variables son referencias.
Sin embargo, si debemos mantener '=' como marco de referencia, entonces sí podemos ver los datos pasados hasta una asignación, y luego no podemos verlos más después de la asignación mientras los datos de la persona que llama permanecen sin cambios. A nivel de comportamiento, esto es pasar por valor siempre que no consideremos que el valor pasado sea compuesto, ya que no podremos mantener parte de él mientras cambiamos la otra parte en una sola asignación (como esa asignación cambia la referencia y el original queda fuera de alcance). También habrá una verruga, en ese caso, las variables en los objetos serán referencias, como lo son todas las variables. Por lo tanto, nos veremos obligados a hablar sobre pasar 'referencias por valor' y a usar locuciones relacionadas.
fuente
Cabe señalar que ni siquiera tiene que usar el método "reemplazar" para cambiar el valor del valor original. Si asigna uno de los valores hash para un hash, está cambiando el valor original.
fuente
Cualquier actualización en el mismo objeto no hará referencias a la nueva memoria ya que todavía está en la misma memoria. Aquí hay algunos ejemplos:
fuente
Sí, pero ....
Ruby pasa una referencia a un objeto y dado que todo en ruby es un objeto, se podría decir que se pasa por referencia.
No estoy de acuerdo con las publicaciones aquí que afirman que es pasar por valor, eso me parece juegos pedantes y simétricos.
Sin embargo, en efecto, "oculta" el comportamiento porque la mayoría de las operaciones que Ruby proporciona "fuera de la caja", por ejemplo, las operaciones de cadena, producen una copia del objeto:
Esto significa que la mayor parte del tiempo, el objeto original se deja sin cambios dando la apariencia de que el rubí es "pasar por valor".
Por supuesto, al diseñar sus propias clases, comprender los detalles de este comportamiento es importante tanto para el comportamiento funcional como para la eficiencia de la memoria y el rendimiento.
fuente