2

我想为一个对象定义一个新的 getter 方法。这是我正在编写的代码irb

> eigenclass = class << self; self; end
> eigenclass.class_eval { attr_reader :foo }

我想这段代码应该foo向 self 对象添加方法。但下一行说不同

puts foo  
=> nil
foo = 1
=> 1       #Why is there no exception?
puts foo  
=> 1
puts @foo 
=> nil

这是为什么?

4

2 回答 2

3

那是因为var = val分配一个局部变量而不是调用一个setter方法。

您需要为其添加前缀self.才能调用 setter(以及实际的 getter,以防您有同名的局部变量),这会引发您期望的错误:

2.0.0p195 :001 > eigenclass = class << self; self; end
 => #<Class:#<Object:0x007fc6f98e24d0>>
2.0.0p195 :002 > eigenclass.class_eval { attr_reader :foo }
 => nil
2.0.0p195 :003 > foo
 => nil
2.0.0p195 :004 > foo = 20
 => 20
2.0.0p195 :005 > foo
 => 20
2.0.0p195 :006 > self.foo
 => nil
2.0.0p195 :007 > self.foo = 20
NoMethodError: undefined method `foo=' for main:Object
    from (irb):7
于 2013-06-29T10:47:45.667 回答
3

你犯了两个错误:a)如果你想要完整的访问器(getter 和 setter),你应该使用:

eigenclass.class_eval { attr_accessor :foo }

b) 如果你想使用 setter 方法,你应该使用self关键字,否则 Ruby 会设置一个局部变量:

self.foo = 1
# => 1
puts @foo
# => 1

或者,不定义 setter,您可以直接设置实例变量:

eigenclass.class_eval { attr_accessor :foo }
@foo = 1
puts @foo
# => 1
于 2013-06-29T10:49:37.057 回答