2010-06-15 51 views
4

我該如何實現類似於下面的內容,以便在塊內設置s變量時,它還會在Topic類中設置@subject實例變量?從塊中設置一個實例變量

class Topic 
    def subject(&blk) 
    blk.call(@subject) if block_given? 
    @subject unless block_given? 
    end 
end 

my_topic = Topic.new 

p my_topic.subject #=> nil 

my_topic.subject do |s| 
    s = ['one', 'two', 'three'] 
    s.pop 
    p s #=> ['one', 'two'] 
end 

p my_topic.subject #=> nil... want it to be ['one, 'two'] 
+1

這不是說它改變了你的問題,但要記住'p s'或'puts s'返回'nil',* not *'s'。 – 2010-06-15 22:12:09

回答

3

你想要做的就是所謂的傳遞引用。這在ruby中是不可能的。您有兩種選擇:

a)執行@subject = blk.call並從塊返回s。通常是最簡單和最乾淨的選項。

b)代替s =@subject =在塊中,然後用instance_eval(&blk)代替blk.call。這將設置@subject變量,但它要求主題方法的用戶知道@subject變量,並且它不允許您多次調用該塊來設置不同的變量。

4

你不能按你想要的方式去做。 block參數引用與實例變量相同的對象,但它們是完全不同的變量,設置一個永遠不會設置另一個。有兩個選項:

  1. 設置變量塊的結果,所以這將是這樣的:

    my_topic.subject do 
        s = ['one', 'two', 'three'] 
        s.pop 
        p s #=> ['one', 'two'] 
        s 
    end 
    
  2. 有:

    class Topic 
        def subject 
        @subject = yield if block_given? 
        @subject unless block_given? 
        end 
    end 
    

    和塊內subject方法instance_eval塊所以塊可以明確設置實例變量

2

除了給出解決方案,如果你知道伊娃是要留字符串/數組/哈希,什麼的,你可以做到以下幾點:

class Topic 
    def subject 
    @subject ||= 'sane default' 
    if block_given? then yield(@subject) 
    else @subject 
    end 
    end 
end 

t = Topic.new 
t.subject { |s| s.replace 'fancy stuff' } 

雖然從我猜你是幹什麼的,這是最合適的代碼:

class Topic 
    def subject 
    return @subject unless block_given? 
    @subject = yield(@subject) 
    end 
end 

t = Topic.new 
t.subject { |s| 'fancy stuff' } 
t.subject { |s| "very #{s}" } 
t.subject # => "very fancy stuff" 

而且,你實際上可以做,沒有一個塊:

class Topic 
    def subject(value = nil) 
    @subject = value % @subject if value 
    @subject = yield @subject if block_given? 
    @subject 
    end 
end 

t = Topic.new 
t.subject 'fancy stuff'     # => "fancy stuff" 
t.subject 'very %s'      # => "very fancy stuff" 
t.subject { |s| s.sub 'fancy', 'freaky' } # => "very freaky stuff" 

請記住,您正在使用的語句p s返回nil