2010-10-11 123 views
0

我有class A紅寶石重寫<<方法

class A 
    attr_reader :b 
    def b=param 
    @b = param 
    print "success" 
    end 
end 

>> a = A.new 
>> a.b = "hello world!" 
#> "success" 
#> "hello world!" 
>> a.b << " and goodbye!" 
#> "helo world! and goodbye!" 

哪裏是我的 「成功」? :)

我想打印「成功」每當我的變量發生變化。

我不能只是寫

def b<<param 
    @b << param 
    print "success" 
end 

回答

5

這裏是你錯過了棘手的部分:變量@b不會在你的例子改變。它仍然包含您最初設置爲的相同字符串對象。這是字符串本身正在改變。這種區別是非常重要的,如果你不掌握它,你會發現你的程序受到千變萬化的困擾。這裏是:

對象和變量是兩個獨立的東西。變量就像插槽一樣,對象是你放入它們的東西。只有=操作員將新對象放入插槽*;其他一切都會將消息發送給插槽中的對象。當您編寫@thing = "hello"時,會將字符串對象"hello"放入插槽@thing中。當你寫@thing << " world"時,你並沒有設置@thing來包含一個新的對象;您將同一對象留在那裏,但將" world"添加到該對象所表示的字符串的末尾。這也意味着任何其他插槽持有相同的對象也會發現他們的字符串改變!

如果你想解決這個問題,你必須使用代理對象(接收<<消息),如ormuriauga described,而不是直接存儲字符串。 Ruby的Delegator可能對此有用。雖然我會建議考慮你是否真的需要這個,因爲它確實使你的設計複雜化,並且通常有更好的方法來做到這一點。

*好的,這有點手搖。還有可以設置實例變量的特殊instance_variable_set方法。但是,如果不使用=運營商eval(),則無法自行編寫該方法。

+0

thanx,這是非常有趣的信息 – fl00r 2010-10-11 21:57:50

+0

除了'instance_variable_set',還有'instance_eval'。但這是你不需要使用的黑魔法。 – 2010-10-14 22:36:44

1

你將不得不作出b是一個類你自己的,你定義所有你想要做你想要的方法。

雖然可以,其實,做這樣的事情:

class A 
    attr_reader :b 
    def initialize 
     @b = "" 
     augment_b! 
    end 

    def augment_b! 
     class << @b 
     alias_method :ltlt, :<< 
     def << args 
      self.ltlt args 
      print "success" 
     end 
     end 
    end 
    def b=param 
    @b = param.to_s 
    augment_b! 
    print "success" 
    end 
end 

我不推薦,雖然它。

讓我們來看看我能否向您解釋這一點。

當你分配給b屬性b=方法被調用。但是當您撥打a.b <<時,您正在訪問b,然後在該對象上調用<<,因此只有在訪問b時才與您的A類接口。我所做的是在b上重新定義了<<方法。

+0

a.b << 'd' =>'SystemStackError:stack level too deep' – fl00r 2010-10-11 21:41:15

+0

是的,對不起。現在修復它。沒有測試過 – einarmagnus 2010-10-11 21:43:30

+0

看起來太hacky :)是不是在Ruby中更簡單的方式來檢查實例變量的訪問和更改? – fl00r 2010-10-11 21:50:41

0

你的方法b沒有叫上再見線。

你定義的零參數的訪問方法被調用,並返回的字符串傳遞給String類的<<方法。

您已經定義了兩種方法具有類似名稱:一種是b,另一個是b=

在第一個方法調用中,您確實調用了b=方法,然後在第二個方法中調用了純文本b。試試這個:

a.b = "hello world!" 
success=> "hello world!" 
a.b = '' << " and goodbye!" 
success=> " and goodbye!" 
+0

但它以某種方式與'b'對齊。調用什麼方法進行分配? setter我想 - 所以在我的二傳手我打電話'print' – fl00r 2010-10-11 21:38:29

+0

好吧,我已經添加了一個更新。有趣的是,注意到具有嵌入空格的方法名稱的創造性解析。 – DigitalRoss 2010-10-11 21:47:33

+0

正如我前面提到的 - 如果我無法控制我的實例變量狀態並通過難以從'=' – fl00r 2010-10-11 21:52:35