@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
O objeto adiciona erros à lang_errors
variável no update_lanugages
método ao realizar um salvamento no @user
objeto, perco os erros que foram inicialmente armazenados na lang_errors
variável.
Embora o que estou tentando fazer seja mais um hack (que parece não estar funcionando). Gostaria de entender por que os valores das variáveis são desbotados. Entendo passar por referência, então eu gostaria de saber como o valor pode ser mantido nessa variável sem ser desbotado.
Respostas:
Na terminologia tradicional, Ruby é estritamente transmitido por valor . Mas não é exatamente isso que você está perguntando aqui.
Ruby não tem nenhum conceito de um valor puro e sem referência, então você certamente não pode passar um para um método. Variáveis são sempre referências a objetos. Para obter um objeto que não será alterado de baixo de você, você precisa duplicar ou clonar o objeto ao qual passou, fornecendo um objeto ao qual ninguém mais se refere. (Mesmo que isso não seja à prova de balas - os dois métodos padrão de clonagem fazem uma cópia superficial, portanto as variáveis de instância do clone ainda apontam para os mesmos objetos que os originais. Se os objetos referenciados pelos ivars sofrerem alterações, isso será ainda aparece na cópia, pois faz referência aos mesmos objetos.)
fonte
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.Os outros respondentes estão todos corretos, mas um amigo me pediu para explicar isso a ele e o que realmente se resume é como Ruby lida com variáveis, então pensei em compartilhar algumas fotos / explicações simples que escrevi para ele (desculpas pelo tamanho e provavelmente alguma simplificação excessiva):
T1: o que acontece quando você atribui uma nova variável
str
a um valor de'foo'
?R:
str
É criado um rótulo chamado que aponta para o objeto'foo'
, que, para o estado desse intérprete Ruby, está no local da memória2000
.P2: O que acontece quando você atribui a variável existente
str
a um novo objeto usando=
?R: O rótulo
str
agora aponta para um objeto diferente.Q3: O que acontece quando você atribuir uma nova variável
=
parastr
?R:
str2
É criado um novo rótulo chamado que aponta para o mesmo objeto questr
.Q4: o que acontece se o objeto referenciado
str
estr2
for alterado?R: Os dois rótulos ainda apontam para o mesmo objeto, mas esse objeto foi alterado (seu conteúdo mudou para outra coisa).
Como isso se relaciona com a pergunta original?
É basicamente o mesmo que acontece no terceiro e quarto trimestres; o método obtém sua própria cópia privada da variável / label (
str2
) que é passada para ele (str
). Ele não pode alterar para qual objeto o rótulostr
aponta , mas pode alterar o conteúdo do objeto ao qual os dois se referem para conter mais:fonte
Ruby usa "passar por referência de objeto"
(Usando a terminologia do Python.)
Dizer que Ruby usa "passagem por valor" ou "passagem por referência" não é realmente descritivo o suficiente para ser útil. Penso que, como a maioria das pessoas conhece atualmente, essa terminologia ("valor" vs "referência") vem do C ++.
No C ++, "passar por valor" significa que a função obtém uma cópia da variável e qualquer alteração na cópia não altera o original. Isso também é verdade para objetos. Se você passar uma variável de objeto por valor, o objeto inteiro (incluindo todos os seus membros) será copiado e quaisquer alterações nos membros não os alterarão no objeto original. (É diferente se você passa um ponteiro por valor, mas Ruby não tem ponteiros, AFAIK.)
Resultado:
No C ++, "passar por referência" significa que a função obtém acesso à variável original. Ele pode atribuir um inteiro inteiro literal novo e a variável original também terá esse valor.
Resultado:
Ruby usa passagem por valor (no sentido de C ++) se o argumento não for um objeto. Mas no Ruby tudo é um objeto, então realmente não há valor no sentido C ++ no Ruby.
Em Ruby, "passar por referência a objeto" (para usar a terminologia do Python) é usado:
Portanto, Ruby não usa "passagem por referência" no sentido de C ++. Se isso acontecesse, a atribuição de um novo objeto a uma variável dentro de uma função faria com que o objeto antigo fosse esquecido após o retorno da função.
Resultado:
* É por isso que, no Ruby, se você deseja modificar um objeto dentro de uma função, mas esquece essas alterações quando a função retorna, você deve fazer explicitamente uma cópia do objeto antes de fazer alterações temporárias na cópia.
fonte
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}"
. Isso imprime "Ruby é passado por valor". Mas a variável dentrofoo
é reatribuída. Sebar
fosse uma matriz, a reatribuição não teria efeitobaz
. Por quê?Ruby é uma passagem por valor. Sempre. Sem exceções. Sem ifs. Sem desculpas.
Aqui está um programa simples que demonstra esse fato:
fonte
Ruby é passar por valor em sentido estrito, MAS os valores são referências.
Isso pode ser chamado de " referência de passagem por valor ". Este artigo tem a melhor explicação que li: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
A referência de passagem por valor pode ser brevemente explicada da seguinte forma:
O comportamento resultante é na verdade uma combinação das definições clássicas de passagem por referência e passagem por valor.
fonte
Já existem ótimas respostas, mas quero postar a definição de um par de autoridades sobre o assunto, mas também espero que alguém possa explicar o que essas autoridades Matz (criador de Ruby) e David Flanagan significaram em seu excelente livro O'Reilly, A linguagem de programação Ruby .
Tudo isso faz sentido para mim até o último parágrafo, e especialmente a última frase. Isso é, na melhor das hipóteses, enganoso e, na pior, confuso. Como, de alguma maneira, as modificações nessa referência de valor passado alteram o objeto subjacente?
fonte
Ruby é passado por referência. Sempre. Sem exceções. Sem ifs. Sem desculpas.
Aqui está um programa simples que demonstra esse fato:
fonte
bar
método. Você está simplesmente modificando o objeto que a referência aponta , mas não a referência em si. A única maneira de modificar as referências no Ruby é por atribuição. Você não pode modificar referências chamando métodos no Ruby porque os métodos só podem ser chamados em objetos e as referências não são objetos no Ruby. Seu exemplo de código demonstra que Ruby compartilhou um estado mutável (que não está sendo discutido aqui), mas não faz nada para esclarecer a distinção entre passagem por valor e passagem por referência.Os parâmetros são uma cópia da referência original. Portanto, você pode alterar valores, mas não pode alterar a referência original.
fonte
Experimente o seguinte: -
o identificador a contém object_id 3 para o objeto de valor 1 e o identificador b contém object_id 5 para o objeto de valor 2.
Agora faça isso:--
Agora, a e b contêm o mesmo object_id 5 que se refere ao objeto de valor 2. Portanto, a variável Ruby contém object_ids para se referir a objetos de valor.
Fazer o seguinte também dá erro: -
mas fazer isso não dará erro: -
Aqui o identificador a retorna o objeto de valor 11, cujo id do objeto é 23, ou seja, object_id 23 está no identificador a. Agora vemos um exemplo usando o método
arg in foo é atribuído com o valor de retorno x. Isso mostra claramente que o argumento é passado pelo valor 11, e o valor 11, por ser um objeto, possui um ID de objeto exclusivo 23.
Agora veja também: -
Aqui, o identificador arg primeiro contém object_id 23 para se referir 11 e após a atribuição interna com o objeto de valor 12, ele contém object_id 25. Mas ele não altera o valor referenciado pelo identificador x usado no método de chamada.
Portanto, Ruby é transmitido por valor e as variáveis Ruby não contêm valores, mas contêm referência ao objeto de valor.
fonte
Ruby é interpretado. Variáveis são referências a dados, mas não os dados em si. Isso facilita o uso da mesma variável para dados de tipos diferentes.
A atribuição de lhs = rhs copia a referência no rhs, não nos dados. Isso difere em outros idiomas, como C, onde a atribuição faz uma cópia de dados para lhs do rhs.
Portanto, para a chamada de função, a variável passada, digamos x, é realmente copiada para uma variável local na função, mas x é uma referência. Haverá duas cópias da referência, ambas fazendo referência aos mesmos dados. Um estará no chamador, um na função.
A atribuição na função copiaria uma nova referência para a versão da função de x. Depois disso, a versão de x do chamador permanece inalterada. Ainda é uma referência aos dados originais.
Por outro lado, o uso do método .replace no x fará com que o ruby faça uma cópia dos dados. Se a substituição for usada antes de qualquer nova atribuição, o chamador também verá os dados mudarem em sua versão.
Da mesma forma, desde que a referência original esteja intacta para a variável passada, as variáveis de instância serão as mesmas que o chamador vê. Na estrutura de um objeto, as variáveis de instância sempre têm os valores de referência mais atualizados, sejam eles fornecidos pelo chamador ou definidos na função para a qual a classe foi passada.
A 'chamada por valor' ou 'chamada por referência' é confusa aqui devido à confusão sobre '=' Nas linguagens compiladas '=' é uma cópia de dados. Aqui nesta linguagem interpretada '=' há uma cópia de referência. No exemplo, você tem a referência passada, seguida por uma cópia de referência '=' que reprova o original passado na referência e, em seguida, as pessoas falando sobre ela como se '=' fossem uma cópia de dados.
Para ser consistente com as definições, devemos continuar com '.replace', pois é uma cópia de dados. Da perspectiva de 'substituir', vemos que isso é de fato passado por referência. Além disso, se percorrermos o depurador, veremos as referências sendo passadas, pois as variáveis são referências.
No entanto, se devemos manter '=' como um quadro de referência, de fato, conseguimos ver os dados passados até uma atribuição e, depois, não conseguimos mais vê-los após a atribuição, enquanto os dados do chamador permanecem inalterados. No nível comportamental, isso passa por valor desde que não consideremos o valor passado como composto - pois não seremos capazes de manter parte dele enquanto alteramos a outra parte em uma única atribuição (como essa atribuição altera a referência e o original fica fora do escopo). Também haverá uma verruga; nesse caso, variáveis em objetos serão referências, assim como todas as variáveis. Portanto, seremos forçados a falar sobre a passagem de 'referências por valor' e teremos que usar locuções relacionadas.
fonte
Observe que você não precisa nem usar o método "substituir" para alterar o valor original do valor. Se você atribuir um dos valores de hash para um hash, estará alterando o valor original.
fonte
Quaisquer atualizações no mesmo objeto não farão as referências à nova memória, pois ela ainda está na mesma memória. Aqui estão alguns exemplos:
fonte
Sim mas ....
Ruby passa uma referência a um objeto e, como tudo em ruby é um objeto, você pode dizer que é passado por referência.
Eu não concordo com as postagens aqui alegando que são passadas por valor, que me parecem jogos pedantes e simétricos.
No entanto, na verdade, "oculta" o comportamento porque a maioria das operações ruby fornece "pronto para uso" - por exemplo, operações de cadeia de caracteres, produzem uma cópia do objeto
Isso significa que, na maioria das vezes, o objeto original permanece inalterado, dando a aparência de que ruby é "transmitido por valor".
Obviamente, ao projetar suas próprias classes, é importante entender os detalhes desse comportamento para o comportamento funcional, a eficiência da memória e o desempenho.
fonte