我很难理解Ruby中的attr_accessor。 有人能给我解释一下吗?
当前回答
我也遇到过这个问题,并写了一篇有点冗长的回答。关于这个问题已经有了一些很好的答案,但如果有人想进一步澄清,我希望我的答案能有所帮助
初始化方法
Initialize允许您在创建实例时将数据设置为对象的实例,而不是每次创建类的新实例时都必须在代码中的单独一行中设置数据。
class Person
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
在上面的代码中,我们使用initialize方法通过initialize中的参数传递Dennis来设置名称“Denis”。如果我们想在不使用initialize方法的情况下设置名称,可以这样做:
class Person
attr_accessor :name
# def initialize(name)
# @name = name
# end
def greeting
"Hello #{name}"
end
end
person = Person.new
person.name = "Dennis"
puts person.greeting
在上面的代码中,我们使用person.name调用attr_accessor setter方法来设置名称,而不是在初始化对象时设置值。
这两个“方法”都做这个工作,但初始化节省了我们的时间和代码行数。
这是初始化的唯一工作。不能将initialize作为方法调用。要实际获取实例对象的值,需要使用getter和setter (attr_reader (get)、attr_writer(set)和attr_accessor(两者))。请参阅下面的详细信息。
getter, Setters (attr_reader, attr_writer, attr_accessor)
getter, attr_reader: getter的全部目的是返回特定实例变量的值。请访问下面的示例代码以了解这方面的详细信息。
class Item
def initialize(item_name, quantity)
@item_name = item_name
@quantity = quantity
end
def item_name
@item_name
end
def quantity
@quantity
end
end
example = Item.new("TV",2)
puts example.item_name
puts example.quantity
在上面的代码中,您在Item“example”的实例上调用方法“item_name”和“quantity”。“举例”。Item_name和example。Quantity”将返回(或“获取”)传递到“示例”中的参数值,并将它们显示在屏幕上。
幸运的是,在Ruby中有一个固有的方法,可以让我们更简洁地编写代码;attr_reader方法。请参阅下面的代码;
class Item
attr_reader :item_name, :quantity
def initialize(item_name, quantity)
@item_name = item_name
@quantity = quantity
end
end
item = Item.new("TV",2)
puts item.item_name
puts item.quantity
这种语法的工作方式完全相同,只是它为我们节省了6行代码。想象一下,如果您有5个可归属于Item类的状态?代码很快就会变长。
Setters, attr_writer: setter方法最初让我感到困惑的是,在我看来,它执行的功能与initialize方法相同。下面我将根据我的理解来解释两者的区别;
如前所述,initialize方法允许您在对象创建时设置对象实例的值。
但是,如果您想稍后(在实例创建之后)设置这些值,或者在初始化后更改它们,该怎么办呢?这是一个使用setter方法的场景。这就是区别。在最初使用attr_writer方法时,不必“设置”特定的状态。
下面的代码是使用setter方法为Item类的这个实例声明值item_name的示例。注意,我们继续使用getter方法attr_reader,这样我们就可以获取值并将它们打印到屏幕上,以防您想自己测试代码。
class Item
attr_reader :item_name
def item_name=(str)
@item_name = (str)
end
end
下面的代码是使用attr_writer来再次缩短代码并节省时间的示例。
class Item
attr_reader :item_name
attr_writer :item_name
end
item = Item.new
puts item.item_name = "TV"
下面的代码重复了上面的初始化示例,其中我们使用initialize在创建时设置对象item_name的值。
class Item
attr_reader :item_name
def initialize(item_name)
@item_name = item_name
end
end
item = Item.new("TV")
puts item.item_name
attr_accessor:执行attr_reader和attr_writer的函数,为您节省了多一行代码。
其他回答
假设您有一个类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文档。
嗯。很多很好的答案。这是我的一些看法。
attr_accessor是一个简单的方法,可以帮助我们清理(DRY-ing)重复的getter和setter方法。 这样我们就可以更专注于编写业务逻辑而不用担心setter和getter。
尽管已有大量的答案,但在我看来,没有一个能解释这里涉及的实际机制。它的元编程;它利用了以下两个事实:
您可以动态地修改模块/类 模块/类声明本身就是可执行代码
好吧,想象一下:
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方法。
我是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
简单地说,它将为类定义setter和getter。
请注意,
attr_reader :v is equivalant to
def v
@v
end
attr_writer :v is equivalant to
def v=(value)
@v=value
end
So
attr_accessor :v which means
attr_reader :v; attr_writer :v
等效于为类定义setter和getter。
推荐文章
- 是否可以在MiniTest中运行单个测试?
- 如何在Ruby中生成a和b之间的随机数?
- 无法安装gem -未能建立gem本地扩展-无法加载这样的文件——mkmf (LoadError)
- 如何在Ruby中创建文件
- 什么是Ruby文件。开放模式和选项?
- Ruby数组到字符串的转换
- 如何分割(块)一个Ruby数组成X元素的部分?
- Ruby中“or”和||的区别?
- 如何测试参数是否存在在轨道
- 在Ruby中不创建新字符串而修饰字符串的规范方法是什么?
- RVM不是一个函数,用' RVM use…’不会起作用
- 了解Gemfile。锁文件
- 如何确定一个数组是否包含另一个数组的所有元素
- 是什么导致这个ActiveRecord::ReadOnlyRecord错误?
- 最好的打印散列的方法