Answers:
假设您有一堂课Person
。
class Person
end
person = Person.new
person.name # => no method error
显然我们从来没有定义方法name
。来做吧。
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"
太棒了 现在我们可以@name
使用reader和writer方法编写和读取实例变量。除非这样做如此频繁,为什么每次都要浪费时间编写这些方法?我们可以更轻松地做到这一点。
class Person
attr_reader :name
attr_writer :name
end
即使这样也可以重复。当您同时希望读者和作家都使用访问器时!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
以相同的方式工作!猜猜是什么:@name
就像我们手动设置时一样,我们的person对象中的实例变量将被设置,因此您可以在其他方法中使用它。
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
方法实际上为您生成方法,阅读其他的答案,书,红宝石文档。
attr_accessor
是在当前类上调用的方法,并且:name
是您传递给该方法的参数。这不是一种特殊的语法,而是一个简单的方法调用。如果您要给它@name
变量,那就没有意义了,因为@name将包含nil
。所以这就像写作attr_accessor nil
。您没有传递给它需要创建的变量,而是传递了要调用该变量的名称。
name
和变量@name
不是同一回事。不要混淆他们。您的类中有实例变量@name
,并且定义attr_reader :name
为可以从外部读取它。没有attr_reader
没有简单的方法,您就可以@name
在课堂之外进行访问。
attr_accessor是只是一种方法。(该链接应提供有关其工作原理的更多见解-查看生成的方法对,并且教程应向您展示如何使用它。)
诀窍是,class
是不是定义在Ruby中(它是在像C ++和Java语言“只是一个定义”),但它是一个用于评估表达。正是在评估期间,attr_accessor
调用该方法的方法又修改了当前类-记住隐式接收器:self.attr_accessor
,self
此时“打开”类对象在哪里。
attr_accessor
和朋友的需求很好:
像Smalltalk一样,Ruby不允许在该对象的方法1之外访问实例变量。也就是说,实例变量不能以x.y
Java甚至Python中常见的形式访问。在Ruby y
中,始终将其作为发送消息(或“调用方法”)。因此,这些attr_*
方法创建了包装器,这些包装器@variable
通过动态创建的方法代理实例访问。
样板糟透了
希望这可以澄清一些小细节。快乐的编码。
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
attr_accessor
终于在这里找到了!尽管它解决了我的问题,但是我很好奇我可以在哪里找到这样的实现示例?
attr_accessor
很简单:
attr_accessor :foo
是以下操作的快捷方式:
def foo=(val)
@foo = val
end
def foo
@foo
end
它只不过是对象的获取器/设置器
基本上,它们伪造了可公开访问的数据属性,而Ruby没有。
它只是为实例变量定义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
上面的大多数答案都使用代码。这个解释试图通过类比/故事不使用任何答案来回答它:
外部团体无法访问CIA内部机密
让我们想象一个真正秘密的地方:中央情报局。除了中央情报局内部的人员,没人知道中央情报局正在发生什么。换句话说,外部人员无法访问CIA中的任何信息。但是因为拥有一个完全秘密的组织并没有好处,所以某些信息可以提供给外界-当然只有CIA希望每个人都知道的事情:例如CIA的局长,比较该部门对环境的友好程度其他信息:例如谁是伊拉克或阿富汗的秘密特工-这些事情在未来150年中可能仍然是秘密。
如果您不在中央情报局范围内,则只能访问它向公众公开的信息。或者,要使用CIA的说法,您只能访问“已清除”的信息。
CIA希望向CIA之外的公众公开的信息称为:属性。
读写属性的含义:
对于CIA,大多数属性是“只读”的。这意味着,如果你是一个党的对外中情局,你可以问: “谁是中情局的局长?” 您会得到一个直接的答案。但是,使用“只读”属性不能做的是在CIA中进行更改更改。例如,您无法打个电话,突然决定让金·卡戴珊(Kim Kardashian)担任导演,或者让帕里斯·希尔顿(Paris Hilton)担任总司令。
如果属性赋予您“写”访问权限,则即使您不在,也可以进行更改。否则,您唯一可以做的就是阅读。
换句话说,访问者允许您对访问组织是外部访问者的组织进行查询或进行更改,具体取决于访问者是读取访问者还是写入访问者。
类内的对象可以轻松地相互访问
类和您访问类中的变量,属性和方法的能力完全一样。HTH!任何问题,请问,希望我能澄清。
如果您熟悉OOP概念,则必须熟悉getter和setter方法。attr_accessor在Ruby中也是如此。
通用的Getter和Setter
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"
设置方法
def name=(val)
@name = val
end
吸气方法
def name
@name
end
Ruby中的Getter和Setter方法
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
我也面临这个问题,并为这个问题写了一个冗长的答案。已经有了一些很好的答案,但是任何需要进一步澄清的人,希望我的答案可以为您提供帮助
初始化方法
初始化允许您在创建实例时将数据设置到对象的实例,而不必每次创建类的新实例时都将它们设置在代码的单独一行上。
class Person
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
在上面的代码中,我们通过使用Initialize中的参数传递Dennis来使用initialize方法设置名称“ 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(both))。有关这些的更多详细信息,请参见下文。
Getters,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
在上面的代码中,您在项目“ example”的实例上调用方法“ item_name”和“ quantity”。“ puts example.item_name”和“ example.quantity”将返回(或“获取”)传递给“ example”的参数的值并将其显示在屏幕上。
幸运的是,在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
这种语法的工作方式完全相同,只是它为我们节省了六行代码。想象一下,是否还有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"
下面的代码是上面初始化示例的重申,在上面的示例中,我们使用初始化在创建时设置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的功能,为您节省一行代码。
我认为使新的Rubyists /程序员(像我自己)感到困惑的部分原因是:
“为什么我不能只告诉实例它具有任何给定的属性(例如名称),然后一次赋予该属性一个值?”
更加概括,但这就是它为我所点击的方式:
鉴于:
class Person
end
我们尚未将Person定义为可以具有名称或其他任何属性的东西。
因此,如果我们那么:
baby = Person.new
...并给他们起个名字...
baby.name = "Ruth"
我们得到一个错误,因为在Rubyland中,对象的Person类还不是与“名称”相关联或不具有“名称”的东西!
但是我们可以使用任何给定的方法(请参阅前面的答案)来表示:“一个Person类(baby
)的实例现在可以具有一个名为'name'的属性,因此,我们不仅有一种语法上的获取和设置该名称,但对我们而言这样做很有意义。”
同样,从稍微不同且更笼统的角度提出这个问题,但我希望这对下一个找到此线程的Person类的下一个实例有所帮助。
理解它的另一种方法是找出具有可以消除哪些错误代码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
“方法”。现在您可以使用后两种方法。
$ bankie.balance
$ bankie.owner
为该模块定义一个命名属性,名称为symbol.id2name,创建一个实例变量(@name)和相应的访问方法以读取它。还创建一个名为name =的方法来设置属性。
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
我是红宝石的新手,只需要处理以下奇怪的事情。将来可能会帮助别人。最后,就像上面提到的那样,其中两个函数(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
属性是可以从对象外部访问的类组件。在许多其他编程语言中,它们被称为属性。通过使用“点符号”可以访问它们的值,如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>
在上面的示例中,c是Car类的实例(对象)。我们尝试从对象外部读取wheel实例变量的值未成功。发生的事情是Ruby尝试在c对象中调用一个名为wheel的方法,但未定义此类方法。简而言之,object_name.attribute_name尝试在对象内调用一个名为attribute_name的方法。要从外部访问wheel变量的值,我们需要使用该名称实现一个实例方法,该方法将在调用时返回该变量的值。这就是所谓的访问器方法。在一般的编程环境中,从对象外部访问实例变量的通常方法是实现访问器方法,也称为getter和setter方法。
在以下示例中,我们向Car类添加了getter和setter方法,以从对象外部访问wheel变量。这不是定义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,它将是只写的。这三种方法本身并不是获取器和设置器,而是在被调用时为我们创建获取器和设置器方法。它们是动态(以编程方式)生成其他方法的方法。这就是所谓的元编程。
第一个(较长)示例未使用Ruby的内置方法,仅当在getter和setter方法中需要附加代码时才应使用。例如,在将值分配给实例变量之前,setter方法可能需要验证数据或进行一些计算。
通过使用instance_variable_get和instance_variable_set内置方法,可以从对象外部访问(读取和写入)实例变量。但是,这几乎是没有道理的,并且通常是一个坏主意,因为绕过封装往往会造成各种破坏。
嗯 很多好的答案。这是我的几分钱。
attr_accessor
是一种简单的方法,可帮助我们清理(干燥)重复的getter and setter
方法。
这样我们就可以将更多精力放在编写业务逻辑上,而不必担心设置者和获取者。