回想一下,在Ruby中,您不能訪問該實例之外的屬性(實例變量)。您只能訪問實例的公共方法。
可以使用attr_accessor
爲你描述充當屬性的類創建一個方法:
irb(main):001:0> class Array
irb(main):002:1> attr_accessor :_meta_
irb(main):003:1> end
=> nil
irb(main):004:0>
irb(main):005:0* x = [1,2,3]
=> [1, 2, 3]
irb(main):006:0> x._meta_ = Hash.new
=> {}
irb(main):007:0> x._meta_[:key] = 'value'
=> "value"
irb(main):008:0>
對於一個簡單的方法做了一個訪問默認初始化,我們需要基本reimplement attr_accessor
ourselves:
class Class
def attr_accessor_with_default accessor, default_value
define_method(accessor) do
name = "@#{accessor}"
instance_variable_set(name, default_value) unless instance_variable_defined?(name)
instance_variable_get(name)
end
define_method("#{accessor}=") do |val|
instance_variable_set("@#{accessor}", val)
end
end
end
class Array
attr_accessor_with_default :_meta_, {}
end
x = [1,2,3]
x._meta_[:key] = 'value'
p x._meta_
y = [4,5,6]
y._meta_[:foo] = 'bar'
p y._meta_
但是等等!輸出不正確:
{:key=>"value"}
{:foo=>"bar", :key=>"value"}
我們已經創建了一個圍繞文字散列默認值的閉包。
一個更好的辦法可能是簡單地使用塊:
class Class
def attr_accessor_with_default accessor, &default_value_block
define_method(accessor) do
name = "@#{accessor}"
instance_variable_set(name, default_value_block.call) unless instance_variable_defined?(name)
instance_variable_get(name)
end
define_method("#{accessor}=") do |val|
instance_variable_set("@#{accessor}", val)
end
end
end
class Array
attr_accessor_with_default :_meta_ do Hash.new end
end
x = [1,2,3]
x._meta_[:key] = 'value'
p x._meta_
y = [4,5,6]
y._meta_[:foo] = 'bar'
p y._meta_
現在的輸出是正確的,因爲Hash.new
被稱爲每次默認值被檢索的時間,而不是每次都重複使用相同的文字哈希值。
{:key=>"value"}
{:foo=>"bar"}
是否有一個原因,你不能簡單地創建一個繼承自Array並添加所需功能的類? – 2010-03-08 02:23:14
這是執行此操作的首選方式,但此問題僅與某些實驗性代碼有關,僅用於測試目的......我將更新該問題。 – dreftymac 2010-03-08 02:47:28
儘管您已經接受了我的回答,但我已經添加了有關如何爲您添加的屬性(根據您的問題更新)設置默認值的說明。 – 2010-03-08 03:44:12