我很难理解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

另一种理解它的方法是通过attr_accessor找出它消除了哪些错误代码。

例子:

class BankAccount    
  def initialize( account_owner )
    @owner = account_owner
    @balance = 0
  end

  def deposit( amount )
    @balance = @balance + amount
  end

  def withdraw( amount )
    @balance = @balance - amount
  end
end

有以下几种方法:

$ bankie = BankAccout.new("Iggy")
$ bankie 
$ bankie.deposit(100)
$ bankie.withdraw(5)

下面的方法会抛出错误:

$ bankie.owner     #undefined method `owner'... 
$ bankie.balance   #undefined method `balance'...

从技术上讲,Owner和balance不是一个方法,而是一个属性。BankAccount类没有def owner和def balance。如果是,那么您可以使用下面的两个命令。但这两个方法都不存在。但是,您可以访问属性,就像通过attr_accessor访问方法一样!!因此有了attr_accessor这个词。属性。访问器。它像访问方法一样访问属性。

添加attr_accessor:balance,:owner允许你读写balance和owner“method”。现在您可以使用最后两个方法。

$ bankie.balance
$ bankie.owner

Attr_accessor(如@pst所述)只是一个方法。它的作用是为你创建更多的方法。

这段代码:

class Foo
  attr_accessor :bar
end

等价于下面的代码:

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

你可以自己用Ruby编写这样的方法:

class Module
  def var( method_name )
    inst_variable_name = "@#{method_name}".to_sym
    define_method method_name do
      instance_variable_get inst_variable_name
    end
    define_method "#{method_name}=" do |new_value|
      instance_variable_set inst_variable_name, new_value
    end
  end
end

class Foo
  var :bar
end

f = Foo.new
p f.bar     #=> nil
f.bar = 42
p f.bar     #=> 42

属性和访问器方法

属性是可以从对象外部访问的类组件。它们在许多其他编程语言中被称为属性。它们的值可以通过使用“点表示法”来访问,如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内置方法,可以从对象外部访问(读和写)实例变量。然而,这很少是合理的,而且通常是一个坏主意,因为绕过封装往往会造成各种破坏。

简单的解释,没有任何代码

以上大多数答案都使用代码。这个解释试图通过一个类比/故事来回答这个问题:

外界不能接触CIA内部机密

Let's imagine a really secret place: the CIA. Nobody knows what's happening in the CIA apart from the people inside the CIA. In other words, external people cannot access any information in the CIA. But because it's no good having an organisation that is completely secret, certain information is made available to the outside world - only things that the CIA wants everyone to know about of course: e.g. the Director of the CIA, how environmentally friendly this department is compared to all other government departments etc. Other information: e.g. who are its covert operatives in Iraq or Afghanistan - these types of things will probably remain a secret for the next 150 years. If you're outside the CIA you can only access the information that it has made available to the public. Or to use CIA parlance you can only access information that is "cleared". The information that the CIA wants to make available to the general public outside the CIA are called: attributes.

读写属性的含义:

In the case of the CIA, most attributes are "read only". This means if you are a party external to the CIA, you can ask: "who is the director of the CIA?" and you will get a straight answer. But what you cannot do with "read only" attributes is to make changes changes in the CIA. e.g. you cannot make a phone call and suddenly decide that you want Kim Kardashian to be the Director, or that you want Paris Hilton to be the Commander in Chief. If the attributes gave you "write" access, then you could make changes if you want to, even if you were outside. Otherwise, the only thing you can do is read. In other words accessors allow you to make inquiries, or to make changes, to organisations that otherwise do not let external people in, depending on whether the accessors are read or write accessors.

类中的对象可以很容易地相互访问

另一方面,如果你已经在中央情报局内部,那么你可以很容易地打电话给你在喀布尔的中央情报局特工,因为这些信息很容易获得,因为你已经在里面了。但如果你不在中情局之外,你根本就没有权限:你不能知道他们是谁(读权限),你也不能改变他们的任务(写权限)。

类也是如此,你可以访问其中的变量、属性和方法。HTH !任何问题,请问,我希望我能澄清。