我很难理解Ruby中的attr_accessor。 有人能给我解释一下吗?
当前回答
我是ruby的新手,不得不理解下面的奇怪之处。也许将来能帮到别人。最后,就像上面提到的,其中两个函数(def myvar, def myvar=)都隐式地访问@myvar,但是这些方法可以被局部声明覆盖。
class Foo
attr_accessor 'myvar'
def initialize
@myvar = "A"
myvar = "B"
puts @myvar # A
puts myvar # B - myvar declared above overrides myvar method
end
def test
puts @myvar # A
puts myvar # A - coming from myvar accessor
myvar = "C" # local myvar overrides accessor
puts @myvar # A
puts myvar # C
send "myvar=", "E" # not running "myvar =", but instead calls setter for @myvar
puts @myvar # E
puts myvar # C
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文档。
尽管已有大量的答案,但在我看来,没有一个能解释这里涉及的实际机制。它的元编程;它利用了以下两个事实:
您可以动态地修改模块/类 模块/类声明本身就是可执行代码
好吧,想象一下:
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方法。
Attr_accessor非常简单:
attr_accessor :foo
是以下操作的快捷方式:
def foo=(val)
@foo = val
end
def foo
@foo
end
它只不过是一个对象的getter/setter
我认为让新手和程序员(比如我自己)困惑的部分原因是:
“为什么我不能告诉实例它有任何给定的属性(例如,名称),并一次性为该属性赋值?”
更一般化一点,但这就是我的想法:
考虑到:
class Person
end
我们还没有将Person定义为可以有名称或任何其他属性的东西。
那么如果我们
baby = Person.new
...试着给它们起个名字…
baby.name = "Ruth"
我们得到一个错误,因为在Rubyland中,对象的Person类不是与“名称”相关联或不具有“名称”的东西……然而!
但是我们可以使用任何给定的方法(参见前面的回答)来说明,“Person类(baby)的实例现在可以有一个名为'name'的属性,因此我们不仅有了获取和设置该名称的语法方法,而且这样做对我们来说是有意义的。”
再一次,从一个稍微不同和更一般的角度来解决这个问题,但我希望这有助于Person类的下一个实例找到这个线程的方法。
它只是一个为实例变量定义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
推荐文章
- 一行if语句不工作
- 在Ruby中将整数转换为十六进制字符串
- 如何记录Ruby代码?
- Ruby:包含的反义词是什么?Ruby数组?
- 在Ruby中,proc和lambda有什么区别?
- 如何传递参数到一个Rake任务与环境在Rails?
- 获取当前正在执行的方法的名称
- 如何在Rails中计算相对时间?
- 在Ruby中使用范围填充数组的正确方法
- “for”和“each”在Ruby中
- 我如何复制一个哈希在Ruby?
- Ruby/Rails:将Date转换为UNIX时间戳
- 我如何编码/解码HTML实体在Ruby?
- Ruby有一个string. startwith ("abc")内置方法吗?
- 如何从URL下载文件并保存在Rails中?