Ruby 为什么我们需要attr_访问器?

Ruby 为什么我们需要attr_访问器?,ruby,attributes,Ruby,Attributes,我无法理解为什么我们需要在类中声明attr_读取器和attr_编写器,或者attr_访问器。我读了和两篇文章,但这些文章主要解释了它们是如何工作的,而不是它们为什么在那里 万一 class Person attr_accessor :age end bob = Person.new bob.age = 99 bob.age 必须告诉Ruby写和读年龄,而不能自动在类外写和读实例变量,这似乎有点多余。为什么我们需要在类中设置reader和writer而不是下面的代码并保存几行代码 clas

我无法理解为什么我们需要在类中声明attr_读取器和attr_编写器,或者attr_访问器。我读了和两篇文章,但这些文章主要解释了它们是如何工作的,而不是它们为什么在那里

万一

class Person
  attr_accessor :age
end

bob = Person.new
bob.age = 99
bob.age
必须告诉Ruby写和读年龄,而不能自动在类外写和读实例变量,这似乎有点多余。为什么我们需要在类中设置reader和writer而不是下面的代码并保存几行代码

class Person
end

bob = Person.new
bob.age = 99
bob.age 

因为它使代码更易于维护

通过这种方式,从类代码中可以清楚地看到您期望发生什么,以及您期望其他类访问这些变量

如果没有这个外部代码,只需访问内部变量,然后如果重构代码并删除或重命名这样的变量,外部代码就会中断

因此,访问器方法清楚地表明您打算让其他类访问这些方法

仅供参考:Ruby非常强大,如果你愿意,你可以按照你想要的方式工作。我不建议这样做,但我要指出这一点,这样您就会明白,为了保持代码的可读性,这是一个明确的选择。但是如果你想看看如何做到这一点,请继续阅读,并尝试运行代码

def putss忽略此方法,只是转储到显示器 元素['output'].html=元素['output'].html+s.to_+s 终止 和服类 def方法_缺少名称,*args 如果名称=~/=$/ 实例_变量_set@{name[0..-2]}.to_sym,args[0] 其他的 实例_变量_get@{name} 终止 终止 终止 类MyClass<开放和服 终止 foo=MyClass.new foo.bar=12 将foo.bar设置为12,它现在={foo.bar} foo.baz=13 将foo.baz设置为13,它现在={foo.baz} 放福。满语从来没有被设定过。。。它等于什么?{foo.满语}
因为它使代码更易于维护

通过这种方式,从类代码中可以清楚地看到您期望发生什么,以及您期望其他类访问这些变量

如果没有这个外部代码,只需访问内部变量,然后如果重构代码并删除或重命名这样的变量,外部代码就会中断

因此,访问器方法清楚地表明您打算让其他类访问这些方法

仅供参考:Ruby非常强大,如果你愿意,你可以按照你想要的方式工作。我不建议这样做,但我要指出这一点,这样您就会明白,为了保持代码的可读性,这是一个明确的选择。但是如果你想看看如何做到这一点,请继续阅读,并尝试运行代码

def putss忽略此方法,只是转储到显示器 元素['output'].html=元素['output'].html+s.to_+s 终止 和服类 def方法_缺少名称,*args 如果名称=~/=$/ 实例_变量_set@{name[0..-2]}.to_sym,args[0] 其他的 实例_变量_get@{name} 终止 终止 终止 类MyClass<开放和服 终止 foo=MyClass.new foo.bar=12 将foo.bar设置为12,它现在={foo.bar} foo.baz=13 将foo.baz设置为13,它现在={foo.baz} 放福。满语从来没有被设定过。。。它等于什么?{foo.满语}
在许多OO语言中,对象的方法和对象的属性之间共享一个表。在Ruby中,所有对象的使用者都应该关心对象的方法。如果您在JS中有此功能:

Tank:
   weight: 123
   moveForward: function()...
在Ruby中,您可以:

Tank:
  ivars:
     @weight = 123
  methods:
     weight: return @weight # or other implementation, or a proxy...
     move_forward...
拥有两个不同表的原因是允许对象决定如何存储数据以及是否存储数据,而不是从外部刺探其属性。这就带来了一个极其重要的优势:保持了。也就是说,从外部使用对象的方法向其发送消息,而不管这些是属性还是方法

这是一个很好的特性,许多其他面向对象语言要么以优化的名义忽略它,要么以避免间接性的名义忽略它,要么以疏忽/无知的方式忽略它。python就是一个很好的例子。我在这里写了一篇关于这个主题的小文章:

回答问题的最后一部分:

为什么我们需要在类中设置reader和writer而不是下面的代码并保存几行代码

class Person
end

bob = Person.new
bob.age = 99
bob.age 
为了防止在JavaScript中一直存在这样的情况,即在对象上寻址方法或属性时,却发现该对象所在位置未定义,这将使应用程序在访问该属性的位置外运行许多行或执行秒

在Ruby中,如果你这样做了,你会得到一个异常,它会把你从自己身上拯救数千次,相信我。事实上,您可以创建一个对象来接受任何getter/setter消息,并且这样的对象已经存在了——它是一个OpenStruct。由于速度问题,这通常不是一个好的做法

[1] pry(main)> require 'ostruct'
=> true
[2] pry(main)> s = OpenStruct.new
=> #<OpenStruct>
[3] pry(main)> s.foo = 1
=> 1
[4] pry(main)> s.bar = 2
=> 2
[5] pry(main)> s.foo
=> 1
[6] pry(main)> s.bar
=> 2
[7] pry(main)> s.x
=> nil
使用meth属性的另一个好处
od生成器是指大多数Ruby文档引擎(RDoc和YARD)都会寻找能够更快地记录对象方法的工具。

在许多OO语言中,对象的方法和对象的属性之间共享一个表。在Ruby中,所有对象的使用者都应该关心对象的方法。如果您在JS中有此功能:

Tank:
   weight: 123
   moveForward: function()...
在Ruby中,您可以:

Tank:
  ivars:
     @weight = 123
  methods:
     weight: return @weight # or other implementation, or a proxy...
     move_forward...
拥有两个不同表的原因是允许对象决定如何存储数据以及是否存储数据,而不是从外部刺探其属性。这就带来了一个极其重要的优势:保持了。也就是说,从外部使用对象的方法向其发送消息,而不管这些是属性还是方法

这是一个很好的特性,许多其他面向对象语言要么以优化的名义忽略它,要么以避免间接性的名义忽略它,要么以疏忽/无知的方式忽略它。python就是一个很好的例子。我在这里写了一篇关于这个主题的小文章:

回答问题的最后一部分:

为什么我们需要在类中设置reader和writer而不是下面的代码并保存几行代码

class Person
end

bob = Person.new
bob.age = 99
bob.age 
为了防止在JavaScript中一直存在这样的情况,即在对象上寻址方法或属性时,却发现该对象所在位置未定义,这将使应用程序在访问该属性的位置外运行许多行或执行秒

在Ruby中,如果你这样做了,你会得到一个异常,它会把你从自己身上拯救数千次,相信我。事实上,您可以创建一个对象来接受任何getter/setter消息,并且这样的对象已经存在了——它是一个OpenStruct。由于速度问题,这通常不是一个好的做法

[1] pry(main)> require 'ostruct'
=> true
[2] pry(main)> s = OpenStruct.new
=> #<OpenStruct>
[3] pry(main)> s.foo = 1
=> 1
[4] pry(main)> s.bar = 2
=> 2
[5] pry(main)> s.foo
=> 1
[6] pry(main)> s.bar
=> 2
[7] pry(main)> s.x
=> nil

使用属性方法生成器的另一个好处是,大多数Ruby文档引擎(RDoc和YARD)都会寻找那些更快地记录对象方法的工具。

OpenStruct的行为类似于OP的第二个代码片段:

require 'ostruct'

bob = OpenStruct.new
bob.age = 99
p bob.age # => 99

所以有一个选择。

OpenStruct的行为类似于OP的第二个代码片段:

require 'ostruct'

bob = OpenStruct.new
bob.age = 99
p bob.age # => 99

所以有一个选择。

我不太明白你的第二个例子。那么,您是说您应该能够随时设置任意实例变量,而无需使用访问器或在构造函数中声明变量?这听起来不是个好主意。我真的推荐你一个很好的问题。我为你的阅读乐趣添加了一个反例:-谢谢@MitchVanDuyn。我没有想到,如果Ruby允许从外部任意创建代码,任何人都可以从外部更改代码。这是有道理的!提供类方法只是为了方便。attr_accessor:a为实例变量@a:def a创建getter和setter方法@A.结束和def a=其他;a=其他;我不太明白你的第二个例子。那么,您是说您应该能够随时设置任意实例变量,而无需使用访问器或在构造函数中声明变量?这听起来不是个好主意。我真的推荐你一个很好的问题。我为你的阅读乐趣添加了一个反例:-谢谢@MitchVanDuyn。我没有想到,如果Ruby允许从外部任意创建代码,任何人都可以从外部更改代码。这是有道理的!提供类方法只是为了方便。attr_accessor:a为实例变量@a:def a创建getter和setter方法@A.结束和def a=其他;a=其他;结束,为您省去了这么做的麻烦。在实际代码中,您应该使用OpenKimono类,而不是OpenKimono类,它的功能几乎相同,但提供了一些额外的访问功能,例如散列式访问器。没错,我刚刚发明了一个类,以说明它可以在没有任何魔法的情况下完成,只是使用ruby的元编程功能。在实际代码中,您应该使用OpenKimono类,而不是OpenKimono类,它的功能几乎相同,但提供了一些额外的访问功能,例如类似哈希的访问器。没错,我刚刚发明了一个类来说明它可以实现,而不需要任何魔法,只是使用ruby的元编程功能。