我很难理解Ruby中的attr_accessor。 有人能给我解释一下吗?
当前回答
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
其他回答
尽管已有大量的答案,但在我看来,没有一个能解释这里涉及的实际机制。它的元编程;它利用了以下两个事实:
您可以动态地修改模块/类 模块/类声明本身就是可执行代码
好吧,想象一下:
class Nameable
def self.named(whatvalue)
define_method :name do whatvalue end
end
end
我们声明了一个名为which的类方法,当用值调用时,创建一个名为name的实例方法,该实例方法返回该值。这就是元编程的部分。
现在我们将子类化这个类:
class Dog < Nameable
named "Fido"
end
我们刚才到底做了什么?在类声明中,可执行代码执行时引用了类。因此,简单的单词named实际上是对类方法named的调用,它继承自Nameable;我们传递字符串“Fido”作为参数。
命名的类方法是做什么的?它创建一个名为name的实例方法,该方法返回该值。现在,在幕后,Dog有一个这样的方法:
def name
"Fido"
end
不相信我?然后看这个小动作:
puts Dog.new.name #=> Fido
我为什么要告诉你这些?因为我刚才对Nameable所做的和attr_accessor对Module所做的几乎完全一样。当您使用attr_accessor时,您正在调用创建实例方法的类方法(继承自Module)。特别是,它为实例属性创建了一个getter和setter方法,实例属性的名称是您提供的参数,这样您就不必自己编写这些getter和setter方法。
它只是一个为实例变量定义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
属性和访问器方法
属性是可以从对象外部访问的类组件。它们在许多其他编程语言中被称为属性。它们的值可以通过使用“点表示法”来访问,如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内置方法,可以从对象外部访问(读和写)实例变量。然而,这很少是合理的,而且通常是一个坏主意,因为绕过封装往往会造成各种破坏。
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.
希望这对你有所帮助!
另一种理解它的方法是通过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
推荐文章
- Rails中的OO设计:在哪里放置东西
- 给定一个类,查看实例是否有方法(Ruby)
- 在日历应用程序中建模重复事件的最佳方法是什么?
- 如何创建一个私有类方法?
- 无法安装pg gem
- 双* (splat)操作符做什么
- 如何使用Ruby on Rails进行HTTP请求?
- 如何从rake任务中提前返回?
- 什么&。(&点)在Ruby中是什么意思?
- 是什么阻碍了Ruby和Python获得V8的Javascript速度?
- 运行pod设置给我“坏的解释器:没有这样的文件或目录”错误
- 在Ubuntu上安装sqlite3-ruby错误
- Ruby有什么Python没有的,反之亦然?
- find_spec_for_exe':无法找到gem bundle (>= 0.a) (gem::GemNotFoundException)
- 将字符串转换为可符号的ruby