Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么要使用Ruby';s属性存取器、属性读取器和属性写入器?_Ruby_Attributes_Attr Accessor - Fatal编程技术网

为什么要使用Ruby';s属性存取器、属性读取器和属性写入器?

为什么要使用Ruby';s属性存取器、属性读取器和属性写入器?,ruby,attributes,attr-accessor,Ruby,Attributes,Attr Accessor,Ruby有这样一种方便快捷的方式来共享实例变量,方法是使用如下键 attr_accessor :var attr_reader :var attr_writer :var 如果我可以简单地使用attr\u访问器,为什么我会选择attr\u reader或attr\u writer?是否有类似表演的东西(我怀疑)?我想这是有原因的,否则他们不会制作这样的键。您并不总是希望实例变量能够从类外部完全访问。在很多情况下,允许对实例变量进行读取访问是有意义的,但对其进行写入可能没有意义(例如,从只读源检

Ruby有这样一种方便快捷的方式来共享实例变量,方法是使用如下键

attr_accessor :var
attr_reader :var
attr_writer :var

如果我可以简单地使用
attr\u访问器
,为什么我会选择
attr\u reader
attr\u writer
?是否有类似表演的东西(我怀疑)?我想这是有原因的,否则他们不会制作这样的键。

您并不总是希望实例变量能够从类外部完全访问。在很多情况下,允许对实例变量进行读取访问是有意义的,但对其进行写入可能没有意义(例如,从只读源检索数据的模型)。在某些情况下,您可能想要相反的结果,但我想不出任何一个不是我头脑中想出来的。

您可以使用不同的访问器将您的意图传达给阅读您的代码的人,并使编写无论如何调用其公共API都能正常工作的类变得更容易

class Person
  attr_accessor :age
  ...
end
在这里,我可以看到,我可以读和写的年龄

class Person
  attr_reader :age
  ...
end
在这里,我可以看到,我可能只阅读年龄。假设它是由这个类的构造函数设置的,然后保持不变。如果age有一个mutator(writer),并且该类是在假定age设置后不会更改的情况下编写的,那么调用该mutator的代码可能会导致错误

但幕后发生了什么

如果你写:

attr_writer :age
attr_reader :age
attr_accessor :age
这可以转化为:

def age=(value)
  @age = value
end
def age
  @age
end
def age=(value)
  @age = value
end

def age
  @age
end
如果你写:

attr_writer :age
attr_reader :age
attr_accessor :age
这可以转化为:

def age=(value)
  @age = value
end
def age
  @age
end
def age=(value)
  @age = value
end

def age
  @age
end
如果你写:

attr_writer :age
attr_reader :age
attr_accessor :age
这可以转化为:

def age=(value)
  @age = value
end
def age
  @age
end
def age=(value)
  @age = value
end

def age
  @age
end

知道了这一点,这里有另一种思考方式:如果你没有属性。。。助手,并且必须自己编写访问器,您是否会编写比您的类需要的更多的访问器?例如,如果只需要读取年龄,是否还要编写一个允许写入年龄的方法?

并非对象的所有属性都要从类外部直接设置。所有实例变量都有编写器,这通常是封装薄弱的标志,也是在类之间引入过多耦合的警告


作为一个实际的例子:我写了一个设计程序,你把物品放在容器里。物品有
attr\u reader:container
,但提供一个writer是没有意义的,因为物品的容器应该改变的唯一时间是当它放置在一个新的容器中时,这也需要定位信息。

以上所有答案都是正确的
attr\u reader
attr\u writer
比手动键入它们是速记的方法更方便编写。除此之外,它们提供了比自己编写方法定义更好的性能。有关更多信息,请参见Aaron Patterson的幻灯片152(从()开始)。

重要的是要了解访问器限制对变量的访问,而不是对其内容的访问。在ruby中,与其他一些OO语言一样,每个变量都是指向实例的指针。因此,例如,如果您有一个散列的属性,并将其设置为“只读”,则始终可以更改其内容,但不能更改指针的内容。 看看这个:

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>'
irb(主):024:0>A类
irb(主):025:1>属性读取器:a
irb(主):026:1>def初始化
irb(main):027:2>@a={a:1,b:2}
irb(主):028:2>结束
irb(主):029:1>结束
=>:初始化
irb(主):030:0>a=a新
=>1,:b=>2}>
irb(主要):031:0>a.a
=>{:a=>1,:b=>2}
irb(main):032:0>a.a.delete(:b)
=> 2
irb(主要):033:0>a.a
=>{:a=>1}
irb(主):034:0>a.a={}
NoMethodError:对于#1}>
来自(irb):34
from/usr/local/bin/irb:11:in`'

如您所见,可以从Hash@a中删除一个键/值对,如添加新键、更改值、eccetera。但不能指向新对象,因为它是只读实例变量

编写
attr\u读取器还有一个显著的性能优势:a
vs.
defa;返回a;结束
@Nitrodist,很有趣。对于Ruby 1.8.7来说,
attr\u reader
defined accessor占用了手动定义访问器86%的时间。对于Ruby 1.9.0来说,
attr\u reader
defined访问器占用了手动定义访问器94%的时间。然而,在我的所有测试中,访问器都很快:一个访问器大约需要820纳秒(Ruby 1.8.7)或440纳秒(Ruby 1.9)。在这些速度下,您需要调用一个访问器数亿次,以获得
attr\u accessor
的性能优势,从而将整个运行时间提高一秒钟。“大概是由此类的构造函数设置的,并保持不变。”这是不准确的。具有读取器的实例变量可能会频繁更改。但是,它们的值只能由类私下更改。您可以使用“,”来添加两个以上的属性,例如:
attr\u访问器:a,:b
,以获取这些年后的价值:根据ruby 2.2.0上的最新基准,attr\u*比getter和setter更快。可能重复