Ruby有这种方便易用的方法来使用像这样的键来共享实例变量
attr_accessor :var
attr_reader :var
attr_writer :var
Run Code Online (Sandbox Code Playgroud)
为什么我会选择attr_reader或者attr_writer我可以简单地使用attr_accessor?有没有像表演(我怀疑)?我想有一个原因,否则他们就不会有这样的钥匙.
Way*_*rad 737
您可以使用不同的访问器将您的意图传达给阅读代码的人,并且无论他们如何调用公共API,都可以更轻松地编写能够正常工作的类.
class Person
attr_accessor :age
...
end
Run Code Online (Sandbox Code Playgroud)
在这里,我可以看到我可以读写年龄.
class Person
attr_reader :age
...
end
Run Code Online (Sandbox Code Playgroud)
在这里,我可以看到我可能只阅读年龄.想象一下,它是由这个类的构造函数设置的,之后保持不变.如果有一个年龄的mutator(作者),并且该类被写成假设年龄,一旦设置,不会改变,那么代码调用该mutator会导致错误.
但是幕后发生了什么?
如果你写:
attr_writer :age
Run Code Online (Sandbox Code Playgroud)
这被翻译成:
def age=(value)
@age = value
end
Run Code Online (Sandbox Code Playgroud)
如果你写:
attr_reader :age
Run Code Online (Sandbox Code Playgroud)
这被翻译成:
def age
@age
end
Run Code Online (Sandbox Code Playgroud)
如果你写:
attr_accessor :age
Run Code Online (Sandbox Code Playgroud)
这被翻译成:
def age=(value)
@age = value
end
def age
@age
end
Run Code Online (Sandbox Code Playgroud)
知道了,这是考虑它的另一种方式:如果你没有attr _...帮助器,并且必须自己编写访问器,你会编写比你需要的更多的访问器吗?例如,如果只需要读取年龄,您是否还会编写一个允许它写入的方法?
Chu*_*uck 15
并非所有对象的属性都是从类外部直接设置的.拥有所有实例变量的编写器通常是弱封装的标志,并警告您在类之间引入了过多的耦合.
作为一个实际例子:我编写了一个设计程序,您可以将项目放在容器中.该项目有attr_reader :container,但提供作者没有意义,因为项目的容器应该更改的唯一时间是它被放置在新的时间,这也需要定位信息.
cor*_*ard 13
您并不总是希望可以从类外部完全访问您的实例变量.有很多情况允许对实例变量进行读访问是有意义的,但写入它可能不会(例如,从只读源检索数据的模型).在某些情况下,你想要相反,但我想不出任何不做的事情.
小智 12
重要的是要理解访问者限制对变量的访问,而不是对其内容的访问.在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>'
Run Code Online (Sandbox Code Playgroud)
正如您所看到的那样,可以从Hash @a中删除一个键/值对,作为添加新键,更改值,eccetera.但是你不能指向一个新对象,因为它是一个只读的实例变量.