>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5
come posso impostare "b" per essere effettivamente "a" in modo che nell'esempio, la variabile a diventi anche quattro. Grazie.ruby variabile come stesso oggetto (puntatori?)
>> a = 5
=> 5
>> b = a
=> 5
>> b = 4
=> 4
>> a
=> 5
come posso impostare "b" per essere effettivamente "a" in modo che nell'esempio, la variabile a diventi anche quattro. Grazie.ruby variabile come stesso oggetto (puntatori?)
class Ref
def initialize val
@val = val
end
attr_accessor :val
def to_s
@val.to_s
end
end
a = Ref.new(4)
b = a
puts a #=> 4
puts b #=> 4
a.val = 5
puts a #=> 5
puts b #=> 5
Quando si esegue b = a
, b
punti per lo stesso oggetto come a
(hanno lo stesso object_id
) .
Quando si esegue a = some_other_thing
, un punto punta a un altro oggetto, mentre b
rimane invariato.
Per Fixnum
, nil
, true
e false
, non è possibile cambiare il valore senza cambiare il object_id
. Tuttavia, è possibile modificare altri oggetti (stringhe, matrici, hash, ecc.) Senza modificare object_id
, poiché non si utilizza il compito (=
).
Esempio con le stringhe:
a = 'abcd'
b = a
puts a #=> abcd
puts b #=> abcd
a.upcase! # changing a
puts a #=> ABCD
puts b #=> ABCD
a = a.downcase # assigning a
puts a #=> abcd
puts b #=> ABCD
Esempio con gli array:
a = [1]
b = a
p a #=> [1]
p b #=> [1]
a << 2 # changing a
p a #=> [1, 2]
p b #=> [1, 2]
a += [3] # assigning a
p a #=> [1, 2, 3]
p b #=> [1, 2]
Non è possibile. Le variabili contengono riferimenti a valori, non riferimenti ad altre variabili.
Ecco ciò che il codice di esempio sta facendo:
a = 5 # Assign the value 5 to the variable named "a".
b = a # Assign the value in the variable "a" (5) to the variable "b".
b = 4 # Assign the value 4 to the variable named "b".
a # Retrieve the value stored in the variable named "a" (5).
si veda questo articolo per una discussione più approfondita del tema: pass by reference or pass by value.
Non c'è modo di fare questo? Affatto? Anche con qualche kludge? Nessun valore che può rappresentare il riferimento? Ho scoperto che posso fare ogni genere di cose pazze in ruby abbastanza facilmente, sono sorpreso che questo non sia possibile. Grazie per la risposta. Voglio sostanzialmente nascondere la variabile reale, potrei adattare il metodo impostato della variabile per impostare anche l'altra variabile? Ciò comporterebbe un sovraccarico? – Orbit
No, non si utilizza la sintassi nell'esempio. Potresti fare alcuni trucchi fantastici con 'eval' per scrivere funzioni che caricano/memorizzano i valori in altre variabili, ma questo è tutto. Vedi questo [discussione di Ruby passare per riferimento vs valore] (http://www.ruby-forum.com/topic/41160). – maerics
Questo è sbagliato! b = un enfaticamente NON assegna 5 a b perché 5 è il valore in a. Il valore in a è un riferimento a un fixnum. b = a assegna quel riferimento a b. –
Non sono un esperto di Ruby. Ma per un Kluge tecnicamente pazzo ... che funzionerebbe solo se ti sei sentito come passare attraverso eval
ogni volta che hai lavorato con una variabile:
>> a = 5
=> 5
>> b = :a
=> :a
>> eval "#{b} = 4"
=> 4
>> eval "#{a}"
=> 4
>> eval "#{b}"
=> 4
Si noti che un uso diretto di b
sarà ancora vi darà :a
e si può 't lo usano nelle espressioni che non sono in eval
:
>> b
=> :a
>> b + 1
NoMethodError: undefined method `+' for :a:Symbol
... e ci sono sicuramente un sacco di avvertimenti. Come quella che avrebbe dovuto catturare l'binding
e passarlo in giro in scenari più complessi ...
'pass parameter by reference' in Ruby?
@ Paul.s ha una risposta per se è possibile modificare il punto della dichiarazione di essere un oggetto wrapper, ma se si può controllare solo il punto di riferimento allora ecco una classe BasicReference
ho provato:
class BasicReference
def initialize(r,b)
@r = r
@b = b
@val = eval "#{@r}", @b
end
def val=(rhs)
@val = eval "#{@r} = #{rhs}", @b
end
def val
@val
end
end
a = 5
puts "Before basic reference"
puts " the value of a is #{a}"
b = BasicReference.new(:a, binding)
b.val = 4
puts "After b.val = 4"
puts " the value of a is #{a}"
puts " the value of b.val is #{b.val}"
Questo uscite:
Before basic reference
the value of a is 5
After b.val = 4
the value of a is 4
the value of b.val is 4
Come è stato notato, la sintassi che si sta utilizzando non può essere eseguita. Basta buttare questo là fuori anche se si potrebbe fare una classe wrapper dipende da cosa si vuole realmente fare
ruby-1.8.7-p334 :007 > class Wrapper
ruby-1.8.7-p334 :008?> attr_accessor :number
ruby-1.8.7-p334 :009?> def initialize(number)
ruby-1.8.7-p334 :010?> @number = number
ruby-1.8.7-p334 :011?> end
ruby-1.8.7-p334 :012?> end
=> nil
ruby-1.8.7-p334 :013 > a = Wrapper.new(4)
=> #<Wrapper:0x100336db8 @number=4>
ruby-1.8.7-p334 :014 > b = a
=> #<Wrapper:0x100336db8 @number=4>
ruby-1.8.7-p334 :015 > a.number = 6
=> 6
ruby-1.8.7-p334 :016 > a
=> #<Wrapper:0x100336db8 @number=6>
ruby-1.8.7-p334 :017 > b
=> #<Wrapper:0x100336db8 @number=6>
È possibile utilizzare le matrici:
a = [5]
b = a
b[0] = 4
puts a[0] #=> 4
Questa idea si basa su this answer.
Solo per riferimento.
>> a = 5
=> 5
>> a.object_id
=> 11
>> b = a
=> 5
>> b.object_id
=> 11
>> b = 4
=> 4
>> b.object_id
=> 9
>> a.object_id
=> 11
# We did change the Fixnum b Object.
>> Fixnum.superclass
=> Integer
>> Integer.superclass
=> Numeric
>> Numeric.superclass
=> Object
>> Object.superclass
=> BasicObject
>> BasicObject.superclass
=> nil
Spero che questo ci consenta di capire meglio gli oggetti in Ruby.
Un'opzione nei casi in cui si ritiene che si desideri avere operazioni puntatore diretto consiste nell'utilizzare il metodo di sostituzione di Hash, Array & stringhe.
Questo è utile per quando si desidera che un metodo restituisca una variabile che un processo che il metodo imposta cambierà in un secondo momento e non vuole il fastidio di utilizzare un oggetto wrapper.
esempio:
def hash_that_will_change_later
params = {}
some_resource.on_change do
params.replace {i: 'got changed'}
end
params
end
a = hash_that_will_change_later
=> {}
some_resource.trigger_change!
a
{i: 'got changed'}
E 'probabilmente meglio in generale l'uso dei wrapper di oggetti espliciti per tali casi, ma questo modello è utile per la costruzione di specifiche/test di roba asincrona.
Suoni come puntatori ... Non è un dev di Ruby, ma non penso che i puntatori siano in Ruby. – Dair
Sì, ci sono dei puntatori in Ruby. Sono riferimenti alle variabili create dai loro tipi di classe. Qui b stava puntando a dove è fino a quando non ha fatto un nuovo puntatore per sé riferimento a Fixnum 4. –
La risposta mostra che = l'assegnazione crea questi puntatori e quando i tipi degli stessi puntano allo stesso riferimento tutto ciò che è necessario è cambiare il riferimento oggetto e entrambi gli stessi tipi hanno uguale riferimento all'oggetto. Tieni presente perché dicono "In Ruby, tutto è un oggetto." Un sacco di verità in questo. –