Var = Array[0] : per valore o per riferimento?

Mi sono trovato a scoprire che nel caso si faccia

list = [[1,0],[1,1]] # => [[1, 0], [1, 1]]
a = list[0] # => [1, 0]
a.delete_at(0) # => 1
a # => [0]
list # => [[0], [1, 1]]

effettuando quindi nell’operazione a=list[0] non assegna il valore, ma
il riferimento, cosa questa che nella documentazione non avevo trovato.

sorgono quindi le domande

  1. questa impostazione vale anche in altri casi?
  2. come effettuare invece un passaggio per valore, senza dover fare

list[0].length.times{|i| a[i]=list[0][i]}

passando tutto il sub-array in blocco non per riferimento?

Ciao Giovanni,

riesco solo a darti una risposta parziale: puoi assegnare ad a il
sub-array in questo modo:

a = list[0].dup

Così facendo il sub-array originale non verrà toccato, visto che
lavorerai su una copia.

Ciao,
Silvano

2009/7/3 Giovanni M. [email protected]:

Ml mailing list
[email protected]
http://lists.ruby-it.org/mailman/listinfo/ml


Considera l’ambiente prima di stampare questa email. Dai, che
l’equazione è semplice: meno A4, più alberi.

. . . Silvano S. . . .
email: [email protected]
site: http://www.sistrall.it

Il giorno 03 Luglio 2009 12.45, Giovanni
Messina[email protected] ha scritto:

sorgono quindi le domande

  1. questa impostazione vale anche in altri casi?

metterla in termini di passaggio per valore o per riferimento rischia
più che altro di confondere le idee; la questione è molto più
semplice: bisogna vedere cosa stai facendo: creando un oggetto nuovo o
modificando un oggetto.

esempio concreto:
a = “ciao”
b = a
a = a.upcase
a => “CIAO”
b => “ciao”

qui non modifichi a, ma lo riassegni.

invece:

a = “ciao”
b = a
a.upcase!
a => “CIAO”
b => “CIAO”

ogni volta che fai questo = quello stai solo creando un riferimento;
ogni volta che fai
questo.metodo_che_modifica_questo_invece_di_creare_un_nuovo_oggetto(),
modifichi l’oggetto, che quindi sarà diverso da qualunque riferimento
si parta per arrivarci.

altro esempio (un errore che commettevo spessissimo anche in python):
a = [[1]] * 5
a => [[1], [1], [1], [1], [1]]
b = a
b => [[1], [1], [1], [1], [1]]
a[0] << 3
a => [[1, 3], [1, 3], [1, 3], [1, 3], [1, 3]]
b => [[1, 3], [1, 3], [1, 3], [1, 3], [1, 3]]

nota che non solo ho modificato b modificando a, ma ogni elemento di a
(o di b) è stato modificato.

questo perché << è un metodo che modifica l’oggetto.

per eliminare ogni dubbio c’è il metodo object_id. ad esempio,
nell’irb che ho aperto in questo momento:

a.object_id => 30095320
b.object_id => 30095320

ma, soprattutto:
a.collect {|x| x.object_id} => [30095330, 30095330, 30095330,
30095330, 30095330]

ovvero, a è un oggetto di tipo array che contiene 5 elementi, i quali
sono 5 riferimenti allo stesso oggetto, cioè [1, 3].

  1. come effettuare invece un passaggio per valore, senza dover fare

list[0].length.times{|i| a[i]=list[0][i]}

sui singoli oggetti puoi usare clone o dup (credo siano alias); però
dup bara, duplica l’oggetto esterno ma non quelli interni:

a = [[1], [1], [1], [1], [1]]
b = a
c = a.dup
a << 2
a => [[1], [1], [1], [1], [1], 2]
b => [[1, 2], [1], [1], [1], [1], 2]
c => [[1], [1], [1], [1], [1]]

però:a[0] << 3
a => [[1, 3], [1], [1], [1], [1], 2]
b => [[1, 3], [1], [1], [1], [1], 2]
c => [[1, 3], [1], [1], [1], [1]]

non so se esiste un metodo già definito per fare la “copia profonda”
di un oggetto; se non esiste, devi farlo tu a mano.

pietro

Giovanni M. wrote:

grazie per le spiegazioni chiare ed esaustive :slight_smile:

Se poi per caso qualcuno sa di un metodo per la “copia profonda” …

Giovanni

Non esiste un metodo per la “copia profonda” per una semplice ragione,
molti oggetti sono instanziati al momento della richiesta (immagina di
avere un oggetto activerecord con dei collegamenti tipo:

Persona
has_many :indirizzi

Indirizzo
has_many :numeri_telefono

quando hai una persona i numeri di telefono non sono ancora caricati, si
caricano nel momento in cui fai persona.indirizzi[x].numeri_telefono
quindi non puoi clonare oggetti che ancora non ci sono (per altro mi
sembra di aver letto che puoi specificare fino a che livello
active_record arriva a leggere quando instanzi un oggetto)

grazie per le spiegazioni chiare ed esaustive :slight_smile:

Se poi per caso qualcuno sa di un metodo per la “copia profonda” …

Giovanni