Ruby é passado por referência ou por valor?

248
@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?

@userO objeto adiciona erros à lang_errorsvariável no update_lanugagesmétodo ao realizar um salvamento no @userobjeto, perco os erros que foram inicialmente armazenados na lang_errorsvariá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.

Sid
fonte
Eu também notar que eu sou capaz de manter esse valor em um objeto clonado
Sid
1
Você deve olhar para a resposta de Abe Voelker. Mas, depois de contornar isso, eis como eu diria. quando você passa um objeto Foo para um procedimento, uma cópia da referência ao objeto é passada, bar, Pass por valor. você não pode alterar o objeto que o Foo aponta, mas pode alterar o conteúdo do objeto para o qual ele aponta. Portanto, se você passar uma matriz, o conteúdo da matriz poderá ser alterado, mas você não poderá alterar qual matriz está sendo referenciada. É bom poder usar os métodos do Foo sem ter que se preocupar em estragar outras dependências do Foo.
bobbdelsol

Respostas:

244

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.)

Mandril
fonte
88
Ruby é uma passagem por valor . Sem ifs. Sem desculpas. Sem exceções. Se você quiser saber se Ruby (ou qualquer outra língua) é passar por referência ou passar por valor , apenas experimentá-lo: def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}".
Jörg W Mittag
95
@ JörgWMittag: Sim, mas a confusão do OP na verdade não é passagem por valor ou passagem por referência no estrito sentido CS das palavras. O que ele estava perdendo é que os "valores" que você está passando são referências. Senti que apenas dizer "É passar por valor" seria pedante e faria um desserviço ao OP, pois não é exatamente isso que ele quis dizer. Mas obrigado pelo esclarecimento, porque é importante para os futuros leitores e eu deveria ter incluído. (Eu estou sempre dividido entre incluindo mais informações e não confundir as pessoas.)
Chuck
16
Discordando de @Jorg. Ruby é passado por referência, ele apenas muda a referência. Tente isso: def foo (bar) bar.replace 'reference' end; baz = 'valor'; foo (baz); coloca "Ruby está passando - # {baz}"
pguardiario
15
@guardiario: Eu acho que é realmente apenas uma questão de definições. Você está usando uma definição de "passagem por referência" que criou pessoalmente, enquanto Jörg está usando a definição tradicional de ciência da computação. Obviamente, não é da minha conta dizer como usar palavras - apenas acho importante explicar o que o termo normalmente significa. Na terminologia tradicional, Ruby é transmitido por valor, mas os próprios valores são referências. Entendo perfeitamente por que você e o OP gostam de pensar nisso como passagem por referência - não é apenas o significado tradicional do termo.
Chuck
7
Tudo no Ruby é um objeto; portanto, o Ruby não passa nem por valor nem por referência, pelo menos no sentido em que esses termos são usados ​​em C ++. "passar por referência a objeto" pode ser uma maneira melhor de descrever o que Ruby faz. No final, porém, a melhor aposta pode ser não colocar muito significado em nenhum desses termos e apenas entender bem o comportamento que realmente acontece.
David Winiecki
424

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 stra um valor de 'foo'?

str = 'foo'
str.object_id # => 2000

insira a descrição da imagem aqui

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ória 2000.


P2: O que acontece quando você atribui a variável existente stra um novo objeto usando =?

str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002

insira a descrição da imagem aqui

R: O rótulo stragora aponta para um objeto diferente.


Q3: O que acontece quando você atribuir uma nova variável =para str?

str2 = str
str2.object_id # => 2002

insira a descrição da imagem aqui

R: str2É criado um novo rótulo chamado que aponta para o mesmo objeto que str.


Q4: o que acontece se o objeto referenciado stre str2for alterado?

str2.replace 'baz'
str2 # => 'baz'
str  # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002

insira a descrição da imagem aqui

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ótulo str aponta , mas pode alterar o conteúdo do objeto ao qual os dois se referem para conter mais:

str = 'foo'

def mutate(str2)
  puts "str2: #{str2.object_id}"
  str2.replace 'bar'
  str2 = 'baz'
  puts "str2: #{str2.object_id}"
end

str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004
Abe Voelker
fonte
1
Robert Heaton também escreveu um blog sobre isso ultimamente: robertheaton.com/2014/07/22/…
Michael Renner
48

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.)

class A {
  public:
    int x;
};

void inc(A arg) {
  arg.x++;
  printf("in inc: %d\n", arg.x); // => 6
}

void inc(A* arg) {
  arg->x++;
  printf("in inc: %d\n", arg->x); // => 1
}

int main() {
  A a;
  a.x = 5;
  inc(a);
  printf("in main: %d\n", a.x); // => 5

  A* b = new A;
  b->x = 0;
  inc(b);
  printf("in main: %d\n", b->x); // => 1

  return 0;
}

Resultado:

in inc: 6
in main: 5
in inc: 1
in main: 1

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.

void replace(A &arg) {
  A newA;
  newA.x = 10;
  arg = newA;
  printf("in replace: %d\n", arg.x);
}

int main() {
  A a;
  a.x = 5;
  replace(a);
  printf("in main: %d\n", a.x);

  return 0;
}

Resultado:

in replace: 10
in main: 10

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:

  • Dentro da função, qualquer membro do objeto pode ter novos valores atribuídos a eles e essas alterações persistirão após o retorno da função. *
  • Dentro da função, atribuir um objeto totalmente novo à variável faz com que a variável pare de fazer referência ao objeto antigo. Mas, após o retorno da função, a variável original ainda fará referência ao objeto antigo.

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.

class A
  attr_accessor :x
end

def inc(arg)
  arg.x += 1
  puts arg.x
end

def replace(arg)
  arg = A.new
  arg.x = 3
  puts arg.x
end

a = A.new
a.x = 1
puts a.x  # 1

inc a     # 2
puts a.x  # 2

replace a # 3
puts a.x  # 2

puts ''

def inc_var(arg)
  arg += 1
  puts arg
end

b = 1     # Even integers are objects in Ruby
puts b    # 1
inc_var b # 2
puts b    # 1

Resultado:

1
2
2
3
2

1
2
1

* É 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.

David Winiecki
fonte
Sua resposta é a melhor. Eu também quero postar um exemplo simples def ch(str) str.reverse! end; str="abc"; ch(str); puts str #=> "cba"
Fangxing
Essa é a resposta correta! Isso também é muito bem explicado aqui: robertheaton.com/2014/07/22/… . Mas o que eu ainda não entendo é o seguinte: 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 dentro fooé reatribuída. Se barfosse uma matriz, a reatribuição não teria efeito baz. Por quê?
haffla #
Eu não entendo sua pergunta. Eu acho que você deveria fazer uma pergunta totalmente nova em vez de fazer comentários aqui.
David Winiecki
42

Ruby é passado por referência ou por valor?

Ruby é uma passagem por valor. Sempre. Sem exceções. Sem ifs. Sem desculpas.

Aqui está um programa simples que demonstra esse fato:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value
Jörg W Mittag
fonte
15
@ DavidJ .: "O erro aqui é que o parâmetro local é reatribuído (apontado para um novo local na memória)" - Isso não é um erro, é a definição de passagem por valor . Se Ruby fosse passado por referência, a reatribuição à ligação do argumento do método local no receptor também teria reatribuído a ligação da variável local no chamador. O que não aconteceu. Portanto, Ruby é uma passagem por valor. O fato de que, se você alterar um valor mutável, o valor muda é completamente irrelevante, é assim que o estado mutável funciona. Ruby não é uma linguagem funcional pura.
Jörg W Mittag
5
Agradecimentos a Jörg por defender a verdadeira definição de "passagem por valor". Está claramente derretendo nosso cérebro quando o valor é de fato uma referência, embora o rubi sempre passe por valor.
Douglas
9
Isso é sofisma. A distinção prática entre "passar por valor" e "passar por referência" é semântica, não sintática. Você diria que as matrizes C são passadas por valor? É claro que não, mesmo quando você passa o nome de uma matriz para uma função, está passando um ponteiro imutável, e apenas os dados aos quais o ponteiro se refere podem ser alterados. Claramente os tipos de valor no Ruby são passados ​​por valor, e os tipos de referência são passados ​​por referência.
Dodgethesteamroller
3
@dodgethesteamroller: Ruby e C são passados ​​por valor. Sempre. Sem exceções, não se não mas. A distinção entre passagem por valor e passagem por referência é se você passa o valor para o qual a referência aponta ou passa a referência. C sempre passa o valor, nunca a referência. O valor pode ou não ser um ponteiro, mas qual é o valor é irrelevante para saber se está sendo passado em primeiro lugar. Ruby também sempre passa o valor, nunca a referência. Esse valor é sempre um ponteiro, mas, novamente, isso é irrelevante.
Jörg W Mittag
44
Essa resposta, apesar de estritamente verdadeira , não é muito útil . O fato de o valor passado ser sempre um ponteiro não é irrelevante. É uma fonte de confusão para as pessoas que estão tentando aprender, e sua resposta não faz absolutamente nada para ajudar com essa confusão.
20

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:

Uma função recebe uma referência (e acessará) o mesmo objeto na memória usado pelo chamador. No entanto, ele não recebe a caixa em que o chamador está armazenando esse objeto; como no valor de passagem por valor, a função fornece sua própria caixa e cria uma nova variável para si mesma.

O comportamento resultante é na verdade uma combinação das definições clássicas de passagem por referência e passagem por valor.

Ari
fonte
"passar referência por valor" é a mesma frase que eu uso para descrever a passagem de argumentos de Ruby. Eu acho que é a frase mais precisa e sucinta.
Wayne Conrad
16

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 .

[de 3.8.1: referências de objeto]

Quando você passa um objeto para um método no Ruby, é uma referência de objeto que é passada para o método. Não é o objeto em si e não é uma referência à referência ao objeto. Outra maneira de dizer isso é que os argumentos do método são passados por valor e não por referência , mas que os valores passados ​​são referências a objetos.

Como as referências a objetos são passadas para métodos, os métodos podem usar essas referências para modificar o objeto subjacente. Essas modificações são visíveis quando o método retorna.

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?

Dominick
fonte
1
Porque a referência não está sendo modificada; o objeto subjacente é.
Dodgethesteamroller
1
Porque o objeto é mutável. Ruby não é uma linguagem puramente funcional. Isso é completamente ortogonal entre passagem por referência e passagem por valor (exceto pelo fato de que, em uma linguagem puramente funcional, passagem por valor e passagem por referência sempre produzem os mesmos resultados, para que o idioma pudesse use um ou ambos sem que você saiba).
Jörg W Mittag
Um bom exemplo seria se, em vez de uma atribuição de variável em uma função, você observar o caso de passar um hash para uma função e fazer uma mesclagem! no hash passado. O hash original acaba modificado.
elc
16

Ruby é passado por referência ou por valor?

Ruby é passado por referência. Sempre. Sem exceções. Sem ifs. Sem desculpas.

Aqui está um programa simples que demonstra esse fato:

def foo(bar)
  bar.object_id
end

baz = 'value'

puts "#{baz.object_id} Ruby is pass-by-reference #{foo(baz)} because object_id's (memory addresses) are always the same ;)"

=> 2279146940 Ruby é referência 2279146940 porque os IDs de objeto (endereços de memória) são sempre os mesmos;)

def bar(babar)
  babar.replace("reference")
end

bar(baz)

puts "some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-#{baz}"

=> algumas pessoas não percebem sua referência porque a atribuição local pode ter precedência, mas é claramente passagem por referência

Brett Allred
fonte
Esta é a única resposta correta e apresenta algumas dicas: Tente a = 'foobar'; b = a; b [5] = 'z', aeb serão modificados.
287
2
@ Martin: seu argumento não é totalmente válido. Vamos analisar sua declaração de código por declaração. a = 'foobar' cria uma nova referência apontando para 'foobar'. b = a cria uma segunda referência aos mesmos dados que a. b [5] = 'z' altera o sexto caractere do valor referenciado por b para a 'z' (o valor que é coincidentemente também referenciado por a é alterado). É por isso que "ambos são modificados" nos seus termos, ou mais precisamente, porque "o valor referenciado por ambas as variáveis ​​é modificado".
Lukas_Skywalker
2
Você não está fazendo nada com a referência no seu barmé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.
Jörg W Mittag 15/02
1
Quando alguém pergunta se um idioma é "passagem por referência", ele geralmente quer saber quando você passa algo para uma função e a função o modifica, será modificado fora da função. Para Ruby, a resposta é 'sim'. Esta resposta é útil para demonstrar que, a resposta da @ JörgWMittag é extremamente inútil.
Toby 1 Kenobi,
@ Toby1Kenobi: É claro que você pode usar sua própria definição pessoal do termo "passagem por valor", que é diferente da definição comum e amplamente usada. No entanto, se você fizer isso, deve estar preparado para confundir as pessoas, especialmente se você deixar de revelar o fato de que está falando de algo muito diferente, em alguns aspectos, até uma noção oposta à de todos os outros. Em particular, "passagem por referência" não se preocupa se o "algo" que é passado pode ou não ser modificado, mas sim com o que esse "algo" é, em particular, se é a referência ...
Jörg W Mittag
8

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.

Rael Gugelmin Cunha
fonte
2

Experimente o seguinte: -

1.object_id
#=> 3

2.object_id
#=> 5

a = 1
#=> 1
a.object_id
#=> 3

b = 2
#=> 2
b.object_id
#=> 5

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:--

a.object_id = 5
#=> error

a = b
#value(object_id) at b copies itself as value(object_id) at a. value object 2 has object_id 5
#=> 2

a.object_id 
#=> 5

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: -

c
#=> error

mas fazer isso não dará erro: -

5.object_id
#=> 11

c = 5
#=> value object 5 provides return type for variable c and saves 5.object_id i.e. 11 at c
#=> 5
c.object_id
#=> 11 

a = c.object_id
#=> object_id of c as a value object changes value at a
#=> 11
11.object_id
#=> 23
a.object_id == 11.object_id
#=> true

a
#=> Value at a
#=> 11

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

def foo(arg)
  p arg
  p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23

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: -

def foo(arg)
  p arg
  p arg.object_id
  arg = 12
  p arg
  p arg.object_id
end

#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
#=> 12
#=> 25
x
#=> 11
x.object_id
#=> 23

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.

Alok Anand
fonte
1

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
1

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.

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"
Don Carr
fonte
Outra coisa que encontrei. Se você está passando um tipo numérico, todos os tipos numéricos são imutáveis ​​e, portanto, são passados ​​por valor. A função de substituição que trabalhou com a cadeia de caracteres acima NÃO funciona com nenhum dos tipos numéricos.
318 Carr Don Don
1
Two references refer to same object as long as there is no reassignment. 

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:

    a = "first string"
    b = a



    b.upcase! 
    => FIRST STRING
    a
    => FIRST STRING

    b = "second string"


a
    => FIRST STRING
    hash = {first_sub_hash: {first_key: "first_value"}}
first_sub_hash = hash[:first_sub_hash]
first_sub_hash[:second_key] = "second_value"

    hash
    => {first_sub_hash: {first_key: "first_value", second_key: "second_value"}}

    def change(first_sub_hash)
    first_sub_hash[:third_key] = "third_value"
    end

    change(first_sub_hash)

    hash
    =>  {first_sub_hash: {first_key: "first_value", second_key: "second_value", third_key: "third_value"}}
Ayman Hussain
fonte
0

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

> astringobject = "lowercase"

> bstringobject = astringobject.upcase
> # bstringobject is a new object created by String.upcase

> puts astringobject
lowercase

> puts bstringobject
LOWERCASE

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.

Tomm P
fonte