Ruby有这种方便易用的方法来使用像这样的键来共享实例变量
attr_accessor :var attr_reader :var attr_writer :var
如果我可以简单地使用 attr_accessor ,为什么我会选择 attr_reader 或 attr_writer ?有没有像表演(我怀疑)?我想有一个原因,否则他们就不会有这样的钥匙 .
attr_accessor
attr_reader
attr_writer
您可以使用不同的访问器将您的意图传达给阅读代码的人,并且无论他们如何调用公共API,都可以更轻松地编写能够正常工作的类 .
class Person attr_accessor :age ... end
在这里,我可以看到我可以读写年龄 .
class Person attr_reader :age ... end
在这里,我可以看到我可能只阅读年龄 . 想象一下,它是由这个类的构造函数设置的,之后保持不变 . 如果有一个年龄的mutator(作者),并且该类被写成假设年龄,一旦设置,不会改变,那么代码调用该mutator会导致错误 .
但是幕后发生了什么?
如果你写:
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 和 attr_writer 比手动输入它们的缩写方法更方便 . 除此之外,它们提供比自己编写方法定义更好的性能 . 有关更多信息,请参阅Aaron Patterson从this talk(PDF)开始的幻灯片152 .
并非所有对象的属性都是从类外部直接设置的 . 拥有所有实例变量的编写器通常是弱封装的标志,并警告您在类之间引入了过多的耦合 .
作为一个实际例子:我编写了一个设计程序,您可以将项目放在容器中 . 该项目有 attr_reader :container ,但它没有't make sense to offer a writer, since the only time the item'容器应该更改时,它被放置在一个新的,这也需要定位信息 .
attr_reader :container
您并不总是希望可以从类外部完全访问您的实例变量 . 在很多情况下,允许对实例变量的读访问是有意义的,但写入它可能不会(例如,从只读源检索数据的模型) . 在某些情况下,你想要相反,但我想不出任何不做的事情 .
重要的是要理解访问者限制对变量的访问,而不是对其内容的访问 . 在ruby中,与其他一些OO语言一样,每个变量都是指向实例的指针 . 因此,例如,如果您具有Hash的属性,并且将其设置为“只读”,则始终可以更改其内容,但不能更改指针的内容 . 看这个:
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>'
正如您所看到的那样,可以从Hash @a中删除一个键/值对,作为添加新键,更改值,eccetera . 但是你不能指向一个新对象,因为它是一个只读的实例变量 .
5 回答
您可以使用不同的访问器将您的意图传达给阅读代码的人,并且无论他们如何调用公共API,都可以更轻松地编写能够正常工作的类 .
在这里,我可以看到我可以读写年龄 .
在这里,我可以看到我可能只阅读年龄 . 想象一下,它是由这个类的构造函数设置的,之后保持不变 . 如果有一个年龄的mutator(作者),并且该类被写成假设年龄,一旦设置,不会改变,那么代码调用该mutator会导致错误 .
但是幕后发生了什么?
如果你写:
这被翻译成:
如果你写:
这被翻译成:
如果你写:
这被翻译成:
知道了,这是考虑它的另一种方式:如果你没有attr _...帮助器,并且必须自己编写访问器,你会编写比你需要的更多的访问器吗?例如,如果只需要读取年龄,您是否还会编写一个允许它写入的方法?
以上所有答案都是正确的;
attr_reader
和attr_writer
比手动输入它们的缩写方法更方便 . 除此之外,它们提供比自己编写方法定义更好的性能 . 有关更多信息,请参阅Aaron Patterson从this talk(PDF)开始的幻灯片152 .并非所有对象的属性都是从类外部直接设置的 . 拥有所有实例变量的编写器通常是弱封装的标志,并警告您在类之间引入了过多的耦合 .
作为一个实际例子:我编写了一个设计程序,您可以将项目放在容器中 . 该项目有
attr_reader :container
,但它没有't make sense to offer a writer, since the only time the item'容器应该更改时,它被放置在一个新的,这也需要定位信息 .您并不总是希望可以从类外部完全访问您的实例变量 . 在很多情况下,允许对实例变量的读访问是有意义的,但写入它可能不会(例如,从只读源检索数据的模型) . 在某些情况下,你想要相反,但我想不出任何不做的事情 .
重要的是要理解访问者限制对变量的访问,而不是对其内容的访问 . 在ruby中,与其他一些OO语言一样,每个变量都是指向实例的指针 . 因此,例如,如果您具有Hash的属性,并且将其设置为“只读”,则始终可以更改其内容,但不能更改指针的内容 . 看这个:
正如您所看到的那样,可以从Hash @a中删除一个键/值对,作为添加新键,更改值,eccetera . 但是你不能指向一个新对象,因为它是一个只读的实例变量 .