@instance_variable和attr_accessor之间的区别

我刚开始学习ruby,我没有看到@instace_variable和使用attr_accessor声明的属性之间的attr_accessor

以下两个类之间有什么区别:

 class MyClass @variable1 end 

 class MyClass attr_accessor :variable1 end 

我在网上搜索了很多教程,每个人都使用不同的符号,它是否需要对ruby版本做任何事情? 我还在StackOverflow中搜索了几个旧线程

什么是Ruby中的attr_accessor?
这两个Ruby类初始化定义之间有什么区别?

但我仍然无法弄清楚什么是最好的使用方法。

实例变量在它所在的对象外部是不可见的; 但是当你创建一个attr_accessor ,它会创建一个实例变量,并使它在对象外部可见(和可编辑)。

实例变量的示例(不是attr_accessor

 class MyClass def initialize @greeting = "hello" end end m = MyClass.new m.greeting #results in the following error: #NoMethodError: undefined method `greeting' for # 

使用attr_accessor示例:

 class MyClass attr_accessor :greeting def initialize @greeting = "hello" end end m2 = MyClass.new m2.greeting = "bonjour" # <-- set the @greeting variable from outside the object m2.greeting #=> "bonjour" <-- didn't blow up as attr_accessor makes the variable accessible from outside the object 

希望能说清楚。

实例变量在类外部不可见。

 class MyClass def initialize @message = "Hello" end end msg = MyClass.new @message #==> nil # This @message belongs to the global object, not msg msg.message #==> NoMethodError: undefined method `message' msg.@message #==> SyntaxError: syntax error, unexpected tIVAR 

现在,您可以随时执行此操作:

 msg.instance_eval { @message } 

但那是尴尬和欺骗。 在别人的课堂上学习可能很有教育意义,但如果你想获得可靠的结果,你的客户代码就不应该这样做。 另一方面,如果您希望客户端能够看到这些值,请不要使用instance_eval ; 相反,定义一个方法来完成这个技巧:

 class MyClass def message return @message end end msg.message # ==> "Hello" 

因为您经常想要这样做,所以Ruby提供了一种快捷方式,使其更容易。 下面的代码与上面的代码具有完全相同的结果:

 class MyClass attr_reader :message end 

那不是一种新的变量; 它只是定义方法的简便方法。 你可以查看msg.methods并看到它现在有一个message方法。

现在,如果你想允许局外人不仅看到实例变量的值,而且还要改变它呢? 为此,您必须为赋值定义不同的方法,名称中包含=

 class MyClass def message=(new_value) @message = new_value end end msg.message = "Good-bye" msg.message # ==> "Good-bye" 

请注意,赋值运算符在这里是半神奇的; 即使msg.message=之间有空格,Ruby仍然知道调用message=方法。 像+=等组合运算符也将触发对该方法的调用。

同样,这是一个常见的设计,因此Ruby也为它提供了一个快捷方式:

 class MyClass attr_writer :message end 

现在,如果你自己使用attr_writer ,你会得到一个可以修改但不见的属性。 有一些奇怪的用例,这就是你想要的,但大多数时候,如果你要让局外人修改变量,你也希望他们能够阅读它。 您不必同时声明attr_readerattr_writer ,您可以像这样声明两者:

 class MyClass attr_accessor :message end 

同样,这只是一个快捷方式,用于定义允许您从类外部获取实例变量的方法。

attr_accesor为您提供了读取和写入实例变量的方法。 实例变量被取消分配以便从外部世界隐藏,因此为了与它们通信,我们应该具有attr _ibute 访问器方法。

在OOPS中,我们有一个称为封装的概念,这意味着, 对象的内部表示通常隐藏在对象定义之外的视图中。 只有对象’本身’可以搞乱自己的内部状态。 外面的世界不能。

每个对象通常由其状态和行为定义 ,在ruby中,实例变量称为对象的内部状态或状态,并且根据OOPS,状态不应被任何其他对象访问,并且这样做我们遵循Encapsulation。

ex: class Foo def initialize(bar) @bar = bar end end

上面,我们定义了一个类Foo,在initialize方法中我们初始化了一个实例变量(属性)或(属性)。 当我们使用new方法创建一个新的ruby对象时,该方法又在内部调用initialize方法,当运行该方法时,声明并初始化@bar实例变量,它将被保存为对象的状态。

每个实例变量都有自己的内部状态,并且对象本身是唯一的,我们在类中定义的每个方法都将根据方法定义和目的改变对象的内部状态。 这里initialize方法做同样的事情,比如创建一个新的实例变量。

 var object = Foo.new(1) # 

在后台,ruby创建了一个实例变量(@bar = 1)并将值存储为对象’object’中对象的状态。 我们可以使用’instance_variables’方法检查它,并且该方法根据对象的当前状态返回包含对象的所有实例变量的数组。

 object.instance_variables #[ [0]: @bar ] 

我们可以在上面看到’@bar’实例变量。 当我们在对象上调用initialize方法时创建的。 默认情况下,这个’@bar’变量不应该是可见的(隐藏的),因此除了对象之外,其他人不能从内部看到它。 但是,一个对象可以乱用它自己的内部状态,这意味着它可以显示或更改值,如果我们给它一个方法这样做,这两个可以通过在类中创建一个新的实例方法来完成。

当我们想通过调用它看到@bar变量时,我们得到一个错误,因为默认情况下我们看不到对象的状态。

 show = object.bar #NoMethodError: undefined method `bar' for # #from (irb):24 #from /home/.rvm/rubies/ruby-2.0.0-p648/bin/irb:12:in `
'

但我们可以通过两种方法访问变量,这两种方法称为setter和getter方法,它们允许对象分别显示或更改其内部状态(实例变量/属性/属性)。

 class Foo def bar @bar end def bar=(new_bar) @bar = new_bar end end 

我们定义了一个getter(bar)和setter(bar =)方法,我们可以用任何方式命名它们,但是里面的实例变量必须与我们想要显示或更改值的实例变量相同。 setter和getters在某种程度上违反了OOPS概念,但它们也是非常强大的方法。

当我们通过重新打开类并定义它们来定义这两个方法时,当我们用方法调用对象时,我们就能够查看实例变量(这里是@foo)并改变它的值。

 object.bar 1 object.bar=2 2 object.bar 2 

这里我们调用bar方法(getter)返回@bar的值,然后我们调用bar = method(setter),我们提供了一个new_value作为参数,它改变了实例变量(@bar)的值,我们可以通过调用bar方法再次查看它。

在ruby中,我们有一个名为attr_accessor的方法,它结合了setter和getter方法,我们将它定义在类中的方法定义之上。 attr_ *方法是创建方法的快捷方式(setter和getter)

 class Foo attr_accessor :bar end 

我们必须提供一个符号(:bar)作为attr_accessor方法的参数,该方法在内部创建setter和getter方法,方法名称为提供的符号名称。

如果我们只需要一个getter方法,我们可以调用attr_reader:bar如果我们只需要一个setter方法,我们可以调用attr_writer:bar

attr_accessor创建attr_writer和attr_reader方法

我们可以提供与逗号分隔的attr_ *方法一样多的实例变量

 class Foo attr_writer :bar attr_reader :bar attr_accessor :bar, :baz end 

因为attr_accessor定义了方法,所以可以从类外部调用它们。 @variable只能从课程内部访问。