2012-04-11 56 views
2

在Ruby中,當定義類爲class_exec的內容時,我得到了意想不到的結果。當我發送到class_exec塊定義一個類變量,類變量正在對Object代替其上class_exec被稱爲類定義:Ruby:定義類變量時class_exec的意外結果

class X; end 
X.class_exec do 
    @@inner_value = "123" 
    def inner_value 
    @@inner_value 
    end 
    def inner_value=(arg) 
    @@inner_value = arg 
    end 
end 

obj1 = X.new 
puts obj1.inner_value 
puts @@inner_value 
puts Object.class_variables 

產地:

123 
123 
@@inner_value 

這確實使用class_eval時不會發生:

X.class_eval(<<-RUBY) 
    @@inner_value = "123" 
    def inner_value 
    @@inner_value 
    end 
    def inner_value=(arg) 
    @@inner_value = arg 
    end 
RUBY 

obj1 = X.new 
puts obj1.inner_value 
puts @@inner_value 
puts Object.class_variables 

產地:

123 

和一個錯誤:

uninitialized class variable @@inner_value in Object (NameError) 

與class_eval的結果是什麼,我會期望在這兩種情況下發生的。我已經在MRI 1.8.7和MRI 1.9.3上試過,並且在Windows XP上運行的結果相同。

這是預期的行爲?如果是這樣,爲什麼?如果沒有,錯誤?

回答

2

類變量綁定到它們在編譯時處聲明的類別。傳遞給class_exec的塊在傳遞給class_exec之前會被編譯,所以類變量綁定到Object

我想你的class_exec是在頂層,這是在對象,所以這就是他們去的地方。爲了證明:

public 

class Object 
    @@x = "ribbit" 
end 

def foo 
    puts "test: #{@@x}" 
end 

x = Object.new 
x.foo 

這就是爲什麼當你使用類模塊中的增值經銷商,包括該模塊(通過附帶的方法)的類都會看到相同的類變量。類變量綁定到模塊。如果你運行這個:

class WithClassVars 
    def self.classvars 
     @classvars ||= {} 
    end 

    def classvars 
     self.class.classvars 
    end 
end 

class A < WithClassVars;end 
class B < WithClassVars;end 

a = A.new 
b = B.new 
a.classvars[:a] = 1 
b.classvars[:a] = 2 

puts a.classvars 
puts b.classvars 

a和b將以相同的數據結束。

如果你通過你的代碼作爲一個字符串class_eval,字符串中class_eval編譯,這樣你就可以確保他們在正確的類,然後。

所以如果你想存儲每類數據,你必須去class_eval,或者使用一些機制來使用類的實例變量。說:

class WithClassVars 
    def self.classvars 
     @classvars ||= {} 
    end 

    def classvars 
     self.class.classvars 
    end 
end 

class A < WithClassVars;end 
class B < WithClassVars;end 

a = A.new 
b = B.new 
a.classvars[:a] = 1 
b.classvars[:a] = 2 

puts a.classvars 
puts b.classvars