ruby-on-rails - linguaggio - ruby on rails tutorial ita




Ruby passa per riferimento o valore? (8)

Ruby passa per riferimento o valore?

Ruby è un riferimento pass-by. Sempre. Nessuna eccezione. No se. No ma

Ecco un semplice programma che dimostra questo fatto:

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 è pass-by-reference 2279146940 perché object_id (indirizzi di memoria) sono sempre gli stessi;)

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}"

=> alcune persone non si rendono conto che è un riferimento perché l'assegnazione locale può avere la precedenza, ma è chiaramente un riferimento pass-by

@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 oggetto @user aggiunge errori alla variabile lang_errors nel metodo update_lanugages . quando lang_errors un salvataggio sull'oggetto @user , perdo gli errori inizialmente memorizzati nella variabile lang_errors .

Anche se quello che sto tentando di fare sarebbe più di un hack (che non sembra funzionare). Mi piacerebbe capire perché i valori delle variabili sono sbiaditi. Capisco passaggio per riferimento, quindi vorrei sapere come il valore può essere contenuto in quella variabile senza essere sbiadito.


Ruby passa per riferimento o valore?

Ruby è un valore pass-by. Sempre. Nessuna eccezione. No se. No ma

Ecco un semplice programma che dimostra questo fatto:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value

È necessario notare che non è necessario utilizzare il metodo "replace" per modificare il valore originale del valore. Se assegni uno dei valori hash per un hash, stai modificando il valore originale.

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

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"

Ci sono già alcune grandi risposte, ma voglio postare la definizione di una coppia di autorità sull'argomento, ma anche sperare che qualcuno possa spiegare cosa hanno detto le autorità Matz (creatore di Ruby) e David Flanagan nel loro eccellente libro O'Reilly, The Ruby Programming Language .

[dalla 3.8.1: Riferimenti agli oggetti]

Quando si passa un oggetto a un metodo in Ruby, si tratta di un riferimento a un oggetto che viene passato al metodo. Non è l'oggetto stesso e non è un riferimento al riferimento all'oggetto. Un altro modo per dire questo è che gli argomenti del metodo vengono passati per valore piuttosto che per riferimento , ma che i valori passati sono riferimenti a oggetti.

Poiché i riferimenti agli oggetti vengono passati ai metodi, i metodi possono utilizzare tali riferimenti per modificare l'oggetto sottostante. Queste modifiche sono quindi visibili al ritorno del metodo.

Tutto ciò ha senso per me fino all'ultimo paragrafo, e specialmente quell'ultima frase. Questo è nel migliore dei casi fuorviante, e in peggio confusione. In che modo, in qualche modo, le modifiche a tale riferimento pass-by-value possono modificare l'oggetto sottostante?


I parametri sono una copia del riferimento originale. Pertanto, è possibile modificare i valori, ma non modificare il riferimento originale.


Nella terminologia tradizionale, Ruby è strettamente pass-by-value . Ma non è proprio quello che stai chiedendo qui.

Ruby non ha alcun concetto di un valore puro, non di riferimento, quindi non puoi certamente passare a un metodo. Le variabili sono sempre riferimenti a oggetti. Per ottenere un oggetto che non cambierà da sotto di te, devi duplicare o clonare l'oggetto che hai passato, dando così un oggetto a cui nessun altro ha un riferimento. (Anche questo non è a prova di proiettile, però - entrambi i metodi di clonazione standard fanno una copia superficiale, quindi le variabili di istanza del clone puntano ancora agli stessi oggetti che gli originali hanno fatto. appaiono ancora nella copia, poiché fa riferimento agli stessi oggetti).


Ruby è interpretato. Le variabili sono riferimenti ai dati, ma non ai dati stessi. Ciò facilita l'utilizzo della stessa variabile per i dati di tipi diversi.

Assegnazione di lhs = rhs quindi copia il riferimento sul rhs, non sui dati. Ciò differisce in altre lingue, come C, dove l'assegnazione fa una copia di dati a lhs da rhs.

Quindi per la chiamata di funzione, la variabile passata, per esempio x, viene effettivamente copiata in una variabile locale nella funzione, ma x è un riferimento. Ci saranno quindi due copie del riferimento, entrambe che fanno riferimento agli stessi dati. Uno sarà nel chiamante, uno nella funzione.

L'assegnazione nella funzione dovrebbe quindi copiare un nuovo riferimento alla versione della funzione di x. Dopo questo la versione del chiamante di x rimane invariata. È ancora un riferimento ai dati originali.

Al contrario, l'uso del metodo .replace su x farà sì che Ruby faccia una copia dei dati. Se la sostituzione viene utilizzata prima di qualsiasi nuova assegnazione, in effetti il ​​chiamante vedrà anche i cambiamenti dei dati nella sua versione.

Allo stesso modo, finché il riferimento originale è intatto per la variabile passata, le variabili di istanza saranno le stesse visualizzate dal chiamante. Nell'ambito di un oggetto, le variabili di istanza hanno sempre i valori di riferimento più aggiornati, indipendentemente dal fatto che siano forniti dal chiamante o impostati nella funzione a cui è stata inoltrata la classe.

La 'chiamata per valore' o 'chiamata per riferimento' è confusa qui a causa della confusione su '=' In lingue compilate '=' è una copia di dati. Qui in questa lingua interpretata '=' è una copia di riferimento. Nell'esempio si ha il riferimento passato seguito da una copia di riferimento anche se '=' che ignora l'originale passato in riferimento, e quindi le persone ne parlano come se '=' fosse una copia di dati.

Per essere coerenti con le definizioni, è necessario mantenere ".replace" dato che si tratta di una copia di dati. Dal punto di vista di ".replace" vediamo che questo è davvero passato per riferimento. Inoltre, se passiamo attraverso il debugger, vediamo i riferimenti passati, poiché le variabili sono riferimenti.

Tuttavia, se dobbiamo mantenere '=' come un quadro di riferimento, allora in effetti possiamo vedere i dati passati fino a un incarico, e quindi non riusciamo a vederli più dopo l'assegnazione mentre i dati del chiamante rimangono invariati. A livello comportamentale, questo valore viene passato per il valore a patto che non consideriamo il valore passato come composito, in quanto non saremo in grado di mantenerne una parte mentre cambiamo l'altra parte in un singolo compito (come quella assegnazione cambia il riferimento e l'originale esce dallo scopo). Ci sarà anche una verruca, in quell'istanza le variabili negli oggetti saranno riferimenti, come tutte le variabili. Quindi saremo costretti a parlare di "riferimenti per valore" e dobbiamo usare le locuzioni correlate.


Ruby è pass-by-value in senso stretto, MA i valori sono riferimenti.

Questo potrebbe essere chiamato " pass-reference-by-value ". Questo articolo ha la migliore spiegazione che ho letto: robertheaton.com/2014/07/22/…

Pass-reference-by-value potrebbe essere brevemente spiegato come segue:

Una funzione riceve un riferimento a (e accederà) allo stesso oggetto in memoria utilizzato dal chiamante. Tuttavia, non riceve la casella in cui il chiamante sta memorizzando questo oggetto; come in pass-value-by-value, la funzione fornisce una propria casella e crea una nuova variabile per se stessa.

Il comportamento risultante è in realtà una combinazione delle definizioni classiche di pass-by-reference e pass-by-value.





pass-by-reference