Answers:
您可以使用不同的访问器将您的意图传达给阅读您的代码的人,并且使编写类的工作变得更容易,无论如何调用他们的公共API都可以正常工作。
class Person
attr_accessor :age
...
end
在这里,我可以看到我可以读写年龄。
class Person
attr_reader :age
...
end
在这里,我可以看到我只能读年龄。想象一下,它是由此类的构造函数设置的,之后保持不变。如果存在年龄的转换器(编写器),并且假定年龄(一旦设定)不变,则编写类,则调用该转换器的代码可能会导致错误。
但是幕后发生了什么?
如果您写:
attr_writer :age
转换为:
def age=(value)
@age = value
end
如果您写:
attr_reader :age
转换为:
def age
@age
end
如果您写:
attr_accessor :age
转换为:
def age=(value)
@age = value
end
def age
@age
end
知道了这一点,这是另一种思考方式:如果您没有attr _...助手,而不得不自己编写访问器,那么您编写的访问器是否会超出您的类所需?例如,如果仅需要读取年龄,您还会编写一种允许写入的方法吗?
attr_reader
定义的accesor占用了手动定义的访问器的86%的时间。对于Ruby 1.9.0,attr_reader
定义的访问器花费的时间是手动定义的访问器的94%。但是,在我所有的测试中,访问器都非常快:访问器大约需要820纳秒(Ruby 1.8.7)或440纳秒(Ruby 1.9)。以这种速度,您需要调用访问器数亿次,attr_accessor
以提高性能,甚至将整体运行时间缩短一秒钟。
attr_accessor :a, :b
重要的是要了解访问器限制对变量的访问,但不限制对变量内容的访问。与其他OO语言一样,在ruby中,每个变量都是指向实例的指针。因此,例如,如果您具有哈希的属性,并且将其设置为“只读”,则始终可以更改其内容,但不能更改指针的内容。看这个:
irb(main):024:0> class A
irb(main):025:1> attr_reader :a
irb(main):026:1> def initialize
irb(main):027:2> @a = {a:1, b:2}
irb(main):028:2> end
irb(main):029:1> end
=> :initialize
irb(main):030:0> a = A.new
=> #<A:0x007ffc5a10fe88 @a={:a=>1, :b=>2}>
irb(main):031:0> a.a
=> {:a=>1, :b=>2}
irb(main):032:0> a.a.delete(:b)
=> 2
irb(main):033:0> a.a
=> {:a=>1}
irb(main):034:0> a.a = {}
NoMethodError: undefined method `a=' for #<A:0x007ffc5a10fe88 @a={:a=>1}>
from (irb):34
from /usr/local/bin/irb:11:in `<main>'
如您所见,有可能从哈希@a中删除键/值对,例如添加新键,更改值等。但是您不能指向新对象,因为它是只读实例变量。