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

如何設置'b'實際上是'a',以便在該示例中,變量a也將變爲4。謝謝。紅寶石變量作爲相同的對象(指針?)

+2

聽起來像指針...不是一個Ruby開發,但我不認爲指針在紅寶石。 – Dair

+0

是的,Ruby中有指針。它們是對由它們的類類型創建的變量的引用。這裏b使其指向其中一個是,直到它做了一個新的指針本身引用Fixnum對象4. –

+0

答案表明,=賦值創建這些指針和時類型相同的都指向相同的所有必須是改變參考對象和兩個相同的類型具有相同的對象引用。請記住他們爲什麼說「在Ruby中,一切都是對象」。在這方面有很多的事實。 –

回答

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 

當你這樣做b = ab指向同一個對象a(它們具有相同的object_id) 。

當你做a = some_other_thing時,a將指向另一個對象,而b保持不變。

對於Fixnumniltruefalse,你不能在不改變object_id改變數值。但是,由於不使用賦值(=),所以可以在不更改object_id,的情況下更改其他對象(字符串,數組,哈希等)。

用繩子

例子:

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 

示例使用數組:

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

你不能。變量保存對值的引用,而不引用其他變量。

這裏就是你的示例代碼是做:

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

請參閱本文的主題進行更深入的討論:pass by reference or pass by value

+0

有沒有辦法做到這一點?在所有?即使有一些kludge?沒有可代表參考的值?我一直在發現,我可以很容易地做出各種瘋狂的紅寶石事情,我很驚訝,這是不可能的。感謝您的答覆。我想基本上隱藏真正的變量,我是否可以調整變量的設置方法以設置另一個變量?這會招致很多開銷嗎? – Orbit

+0

不,不使用你的例子中的語法。你可以做一些花哨的技巧與'eval'編寫加載/存儲的值在其他變量,但僅此而已功能。看到這個[關於Ruby通過引用vs值的討論](http://www.ruby-forum.com/topic/41160)。 – maerics

+0

這是錯的! b = a最強調不把b賦值5,因爲5是a中的值。 a中的值是對fixnum的引用。 b = a分配對b的引用。 –

0

我不是Ruby的專家。但是,對於一個技術上瘋狂克魯格...這將只有當你覺得通過eval每次你用可變工作時間去工作:

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

注意的b直接使用還是會給你:a,你可以「T用它不在eval表達式:

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

...當然也有一噸需要注意的地方。比如,你不得不捕捉binding和更復雜的場景到處傳遞它...

'pass parameter by reference' in Ruby?

@ Paul.s有,如果你可以改變聲明的時候是一個答案包裝對象,但如果你只能控制的參考點,然後這裏有一個BasicReference類我想:

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

此輸出:

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

如前所述,您正在使用的語法無法完成。剛拋出這個在那裏,雖然你可以做一個包裝類,這取決於你真正想做的事

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

您可以使用數組:

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

此想法是基於this answer

1

只爲參考的緣故。

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

我希望這可以讓我們更好地理解Ruby中的對象。在你覺得你想有直接的指針操作的情況下

1

一種選擇是使用哈希表,數組&字符串的替代方法。

這是因爲當你想有一個方法返回一個變量,一個進程的方法設置將在日後發生變化,並且不希望使用一個包裝對象的煩惱有用。

例如:

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

它可能會更好通常使用明確的對象包裝對於這種情況,但這種模式是建築規格/異步測試的東西有用。