2011-07-20 104 views
3

比較下面兩段代碼:問題傳遞紅寶石

class Logger 
    def self.add_logging(id_string) 
    define_method(:log) do |msg| 
     now = Time.now.strftime("%H:%M:%S") 
     STDERR.puts "#{now}-#{id_string}: #{self} (#{msg})" 
    end 
    end 
end 

class Song < Logger 
    add_logging "Tune" 
end 

song = Song.new 
song.log("rock on") 

class Logger 
    def self.add_logging(id_string) 
    def log(msg) 
     now = Time.now.strftime("%m") 
     puts "#{now}-#{id_string}: #{self}(#{msg})" 
    end 
    end 
end 

class Song < Logger 
    add_logging "Tune" 
end 

s = Song.new 

s.log("can't smile with you") 
#=> NameError: undefined local variable or method `id_string' for #<Song:0x000001018aad70> 

我想不通爲什麼第二種情況下得到NameError錯誤,爲什麼ID_STRING可以」不會傳遞給它。

回答

0

試試這個類變量?

class Logger 
    def self.add_logging(id_string) 
    @@my_id = id_string 
    define_method(:log) do |msg| 
     now = Time.now.strftime("%H:%M:%S") 
     STDERR.puts "#{now}-#{@@my_id}: #{self} (#{msg})" 
    end 
    end 
end 
1

id_string是方法add_logging的本地方法。在你的後一種實現中,日誌方法不能看到它,因此錯誤。在前一個實現中,您可以在 add_logging內動態定義日誌方法

換句話說,局部變量在其定義的範圍內(在這種情況下是方法)是可見的。在後一種實現中,您有嵌套的作用域(=方法中的方法聲明),並且內部作用域不能訪問局部於外部作用域的變量。

正如@stef的回答中所建議的那樣,您可能會解決這個問題,因爲我擴大了變量的範圍。我建議儘可能將變量作用域保持爲'緊密',因此更喜歡你的第一個實現。

3

def創建一個新的範圍;一個塊不會。新的範圍會切斷周圍變量的可見性。紅寶石還有另外兩個'新的範圍創建者':類和模塊。

x = 10 

3.times do |i| 
    puts i * x 
end 

def do_stuff 
    puts x * 10 
end 

do_stuff 

--output:-- 
0 
10 
20 
`do_stuff': undefined local variable or method `x' 
0

類別變量應該避免在紅寶石由於其問題性質。 ruby的方式是使用'類實例變量'來代替。