2011-08-24 18 views
5
>> a = 5 
=> 5 
>> b = a 
=> 5 
>> b = 4 
=> 4 
>> a 
=> 5 

jak ustawić "b" tak, aby rzeczywiście był "a", tak aby w przykładzie zmienna a również stała się czwarta. dzięki.Zmienna ruby ​​jako ten sam obiekt (wskaźniki?)

+2

Brzmi jak wskaźniki ... Nie jest to dev z Ruby, ale nie sądzę, że wskaźniki są w Ruby. – Dair

+0

Tak, istnieją wskaźniki w języku Ruby. Są to odniesienia do zmiennych tworzonych przez ich typy klas. Tutaj b wskazywało, gdzie a jest, dopóki nie zrobiło nowego wskaźnika dla siebie odwołującego się do Fixnum 4. –

+0

Odpowiedź pokazuje, że = przydział tworzy te wskaźniki, a gdy typy tego samego wskazują na to samo odniesienie, wszystko, co konieczne, to zmienić odniesienie obiekt i oba te same typy mają jednakowe odniesienie do obiektu. Pamiętaj, dlaczego mówią "W Ruby wszystko jest przedmiotem". Mnóstwo prawdy. –

Odpowiedz

5
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 

Kiedy robisz b = a, b punkty do tego samego obiektu jako a (mają taką samą object_id) .

Po wykonaniu a = some_other_thing, a wskaże inny obiekt, podczas gdy b pozostanie niezmieniony.

Dla Fixnum, nil, true i false, nie można zmienić wartość bez zmiany object_id. Można jednak zmieniać inne obiekty (łańcuchy, tablice, hasze itp.) Bez zmieniania object_id, , ponieważ nie używasz przypisania (=).

Przykład z ciągów:

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 

Przykład z tablicami:

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] 
2

Nie możesz. Zmienne zawierają odniesienia do wartości, a nie odniesienia do innych zmiennych.

Oto przykład kodu, co się robi:

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

Zobacz ten artykuł do bardziej pogłębionej dyskusji na temat: pass by reference or pass by value.

+0

Nie ma sposobu, aby to zrobić? W ogóle? Nawet z odrobiną kludu? Brak wartości, która może reprezentować odniesienie? Zauważyłem, że potrafię dość łatwo wykonywać różne rodzaje szalonych rzeczy w rubinie, jestem zaskoczony, że nie jest to możliwe. Dzięki za twoją odpowiedź. Chcę w zasadzie ukryć zmienną rzeczywistą, czy mogę dostosować ustawioną metodę zmiennej, aby ustawić inną zmienną? Czy to przyniesie wiele kosztów? – Orbit

+0

Nie, nie używając składni w twoim przykładzie. Możesz zrobić kilka wymyślnych sztuczek z 'eval', aby pisać funkcje, które ładują/przechowują wartości w innych zmiennych, ale to wszystko. Zobacz [dyskusja na temat przejścia Rubiego przez odniesienie do wartości] (http://www.ruby-forum.com/topic/41160). – maerics

+0

To jest złe! b = najbardziej zdecydowanie nie przypisuje 5 do b, ponieważ 5 jest wartością w. Wartość w a jest odniesieniem do fixnum. b = a przypisuje to odniesienie do b. –

0

Nie jestem ekspertem od Rubiego. Ale dla technicznie szalony Kluge ... to będzie działać tylko wtedy, gdy czułeś się przechodząc przez eval każdym razem, kiedy pracował ze zmienną:

>> a = 5 
=> 5 
>> b = :a 
=> :a 
>> eval "#{b} = 4" 
=> 4 
>> eval "#{a}" 
=> 4 
>> eval "#{b}" 
=> 4 

Należy pamiętać, że bezpośrednie wykorzystanie b będzie nadal daje :a i można „t go używać w wyrażeniach, które nie są w eval:

>> b 
=> :a 
>> b + 1 
NoMethodError: undefined method `+' for :a:Symbol 

... i nie ma na pewno mnóstwo zastrzeżeń. Taki jak trzeba by uchwycić binding i przekazać go wokół w bardziej złożonych scenariuszy ...

'pass parameter by reference' in Ruby?

@ Paul.s ma odpowiedź na czy można zmienić punkt deklaracji być obiekt wrapper, ale jeśli można tylko kontrolować punkt odniesienia następnie oto BasicReference klasa próbowałem:

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

This wyjścia:

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 
1

Jak już wspomniano, składnia, której używasz, nie może zostać wykonana. Po prostu rzuca to na zewnątrz tam chociaż można uczynić klasy otoki to zależy od tego, co rzeczywiście chcesz zrobić

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

Można używać tablic:

a = [5] 
b = a 
b[0] = 4 
puts a[0] #=> 4 

Idea ta opiera się na this answer.

1

Tylko ze względu na odniesienie.

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

Mam nadzieję, że da nam to trochę więcej zrozumienia na temat obiektów w Ruby.

1

Jedną z opcji w przypadkach, w których wydaje się, że użytkownik chciałby wykonywać operacje bezpośrednio na wskaźnikach, jest użycie metody zamiany łańcuchów Hasch, Array &.

przydaje się wtedy, gdy chciałbyś, aby metoda zwróciła zmienną, której proces, który konfiguruje, zmieni się w późniejszym terminie i nie będzie chciał irytować używania obiektu opakowania.

przykład:

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

To chyba lepiej ogólnie używać jawnych owijarki obiektów takich przypadkach, ale wzór ten jest przydatny do specyfikacji testów/asynchronicznym rzeczy budowlanych.

Powiązane problemy