我很难理解Ruby中的attr_accessor。 有人能给我解释一下吗?


当前回答

嗯。很多很好的答案。这是我的一些看法。

attr_accessor是一个简单的方法,可以帮助我们清理(DRY-ing)重复的getter和setter方法。 这样我们就可以更专注于编写业务逻辑而不用担心setter和getter。

其他回答

它只是一个为实例变量定义getter和setter方法的方法。一个示例实现如下:

def self.attr_accessor(*names)
  names.each do |name|
    define_method(name) {instance_variable_get("@#{name}")} # This is the getter
    define_method("#{name}=") {|arg| instance_variable_set("@#{name}", arg)} # This is the setter
  end
end

假设您有一个类Person。

class Person
end

person = Person.new
person.name # => no method error

显然,我们没有定义方法名。我们来做一下。

class Person
  def name
    @name # simply returning an instance variable @name
  end
end

person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error

啊哈,我们可以读名字,但这并不意味着我们可以分配名字。这是两种不同的方法。前者称为读者,后者称为作者。我们还没有创建写入器,我们来做一下。

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

太棒了。现在我们可以使用reader和writer方法写入和读取实例变量@name。不过,这是经常做的,为什么每次都浪费时间写这些方法呢?我们可以做得简单些。

class Person
  attr_reader :name
  attr_writer :name
end

即使这样也会重复。当你同时需要读取器和写入器时,只需使用访问器!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

原理是一样的!你猜怎么着:person对象中的实例变量@name将被设置,就像我们手动设置时一样,所以你可以在其他方法中使用它。

class Person
  attr_accessor :name

  def greeting
    "Hello #{@name}"
  end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

就是这样。为了理解attr_reader, attr_writer和attr_accessor方法是如何为你生成方法的,请阅读其他答案,书籍,ruby文档。

The main functionality of attr_accessor over the other ones is the capability of accessing data from other files. So you usually would have attr_reader or attr_writer but the good news is that Ruby lets you combine these two together with attr_accessor. I think of it as my to go method because it is more well rounded or versatile. Also, peep in mind that in Rails, this is eliminated because it does it for you in the back end. So in other words: you are better off using attr_acessor over the other two because you don't have to worry about being to specific, the accessor covers it all. I know this is more of a general explanation but it helped me as a beginner.

希望这对你有所帮助!

属性和访问器方法

属性是可以从对象外部访问的类组件。它们在许多其他编程语言中被称为属性。它们的值可以通过使用“点表示法”来访问,如object_name.attribute_name。与Python和其他一些语言不同,Ruby不允许从对象外部直接访问实例变量。

class Car
  def initialize
    @wheels = 4  # This is an instance variable
  end
end

c = Car.new
c.wheels     # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>

In the above example, c is an instance (object) of the Car class. We tried unsuccessfully to read the value of the wheels instance variable from outside the object. What happened is that Ruby attempted to call a method named wheels within the c object, but no such method was defined. In short, object_name.attribute_name tries to call a method named attribute_name within the object. To access the value of the wheels variable from the outside, we need to implement an instance method by that name, which will return the value of that variable when called. That's called an accessor method. In the general programming context, the usual way to access an instance variable from outside the object is to implement accessor methods, also known as getter and setter methods. A getter allows the value of a variable defined within a class to be read from the outside and a setter allows it to be written from the outside.

在下面的示例中,我们向Car类添加了getter和setter方法,以便从对象外部访问wheels变量。这不是定义getter和setter的“Ruby方式”;它只是用来说明getter和setter方法的作用。

class Car
  def wheels  # getter method
    @wheels
  end

  def wheels=(val)  # setter method
    @wheels = val
  end
end

f = Car.new
f.wheels = 4  # The setter method was invoked
f.wheels  # The getter method was invoked
# Output: => 4

上面的示例可以工作,类似的代码通常用于创建其他语言中的getter和setter方法。但是,Ruby提供了一种更简单的方法:三个内置方法,分别是attr_reader、attr_writer和attr_acessor。attr_reader方法使实例变量从外部可读,attr_writer使实例变量可写,attr_acessor使实例变量可读可写。

上面的例子可以写成这样。

class Car
  attr_accessor :wheels
end

f = Car.new
f.wheels = 4
f.wheels  # Output: => 4

在上面的例子中,wheels属性在对象外部是可读和可写的。如果我们使用attr_reader而不是attr_accessor,它将是只读的。如果我们使用attr_writer,它将只写。这三个方法本身并不是getter和setter,但是当调用时,它们为我们创建了getter和setter方法。它们是动态(以编程方式)生成其他方法的方法;这就是所谓的元编程。

第一个(较长的)示例没有使用Ruby的内置方法,应该仅在getter和setter方法中需要额外代码时使用。例如,setter方法可能需要在将值分配给实例变量之前验证数据或进行一些计算。

通过使用instance_variable_get和instance_variable_set内置方法,可以从对象外部访问(读和写)实例变量。然而,这很少是合理的,而且通常是一个坏主意,因为绕过封装往往会造成各种破坏。

嗯。很多很好的答案。这是我的一些看法。

attr_accessor是一个简单的方法,可以帮助我们清理(DRY-ing)重复的getter和setter方法。 这样我们就可以更专注于编写业务逻辑而不用担心setter和getter。