@instance_variable和attr_accessor之间的区别

Raj*_*ula 29 ruby

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

以下两个类有什么区别:

class MyClass  
  @variable1 
end
Run Code Online (Sandbox Code Playgroud)

class MyClass
  attr_accessor :variable1
end
Run Code Online (Sandbox Code Playgroud)

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

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

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

Nat*_*yer 51

实例变量在它所在的对象外部是不可见的; 但是当你创建一个时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 #<MyClass:0x007f9e5109c058 @greeting="hello">
Run Code Online (Sandbox Code Playgroud)

示例使用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
Run Code Online (Sandbox Code Playgroud)

希望能说清楚.

  • 实际上我来自java背景,在java中,可以使用访问修饰符(public,protected)使实例变量对外部可见,这就是为什么我无法理解为什么无法从外部访问ruby中的实例变量.谢谢你的解释,干杯! (3认同)

Mar*_*eed 27

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

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
Run Code Online (Sandbox Code Playgroud)

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

msg.instance_eval { @message }
Run Code Online (Sandbox Code Playgroud)

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

class MyClass
  def message 
    return @message
  end
end
msg.message
# ==> "Hello"
Run Code Online (Sandbox Code Playgroud)

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

class MyClass
  attr_reader :message
end
Run Code Online (Sandbox Code Playgroud)

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

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

class MyClass
  def message=(new_value)
    @message = new_value
  end
end
msg.message = "Good-bye"
msg.message
# ==> "Good-bye"
Run Code Online (Sandbox Code Playgroud)

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

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

class MyClass
  attr_writer :message
end
Run Code Online (Sandbox Code Playgroud)

现在,如果您attr_writer单独使用,您将获得一个可以修改但未见的属性.有一些奇怪的用例,这就是你想要的,但大多数时候,如果你要让外人修改变量,你也希望它们能够读取它.而不是必须同时声明an attr_reader和an attr_writer,你可以像这样声明两者:

class MyClass
  attr_accessor :message
end
Run Code Online (Sandbox Code Playgroud)

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

  • 这是一个更好,更详细的答案,可以清楚地回答来自其他语言的人的问题 - 谢谢! (4认同)

meg*_*gas 8

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