attr_accessor 是 Ruby 中一个用于创建getter 和 setter 方法的方法。
假设你有一个类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
哦,我们可以读取名称,但这并不意味着我们可以分配名称。这是两种不同的方法。前者称为reader,后者称为writer。我们还没有创建writer,所以让我们创建它。
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"
太棒了。现在我们可以使用读取器和写入器方法来编写和读取实例变量@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"
同样的方式!猜猜看:我们人物对象中的实例变量@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
是一个被调用在当前类上的方法,而:name
则是你传递给该方法的参数。它不是特殊的语法,而是一个简单的方法调用。如果你给它传递@name
变量,那将没有意义,因为@name
会包含nil
。这就像写下attr_accessor nil
一样。你传递的不是需要被创建的变量,而是你想要该变量被称呼的名称。 - Max Chernyakname
方法和 @name
变量不是同一个东西。不要混淆它们。在你的类中有实例变量 @name
,你定义了 attr_reader :name
来能够从外部读取它。如果没有 attr_reader
,你很难在类外部访问 @name
。 - Max Chernyakattr_accessor只是一个方法。 (链接应提供更多关于它如何工作的见解-查看生成的方法对和教程应该向您展示如何使用它。)
诀窍在于,在Ruby中,class
不是一个定义(在C++和Java等语言中它是“只是一个定义”),而是一个评估表达式。在此评估过程中,会调用attr_accessor
方法,从而修改当前类-请记住隐式接收者:self.attr_accessor
,其中self
是此时的“开放”类对象。
需要attr_accessor
和相关方法的原因是:
x.y
的形式访问实例变量。在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
的实现草图,最终在这里找到了!虽然它解决了我的问题,但我很好奇在哪里(书籍/官方文档)可以找到像这样的实现示例? - Wasif Hossainattr_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
如果你熟悉面向对象编程的概念,你一定熟悉getter和setter方法。在Ruby中,attr_accessor做了同样的事情。
通用方式下的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"
大部分的回答都使用了代码,这个解释尝试通过一个比喻/故事来回答,而不使用任何代码:
外部人员无法访问内部的CIA机密
让我们想象一个非常神秘的地方:中央情报局(CIA)。除了CIA内部的人员之外,没有人知道CIA内部发生了什么。换句话说,外部人员无法访问CIA中的任何信息。但是因为拥有一个完全保密的组织没有任何好处,某些信息会向外界公开 - 当然只有CIA希望每个人都知道的内容:例如CIA局长是谁、这个部门与其他政府部门相比的环保程度等等。其他信息,例如在伊拉克或阿富汗的隐蔽特工是谁,这些类型的事情可能会保持秘密150年。
如果你不是CIA内部人员,你只能访问它向公众提供的信息。或者用CIA的专业术语来说,你只能访问被“批准”的信息。
CIA希望向外界公开的信息被称为: 属性(attributes)。
读取和写入属性的含义:
就CIA而言,大多数属性都是“只读”的。这意味着如果你是CIA之外的人员,你可以询问:“谁是CIA局长?”然后你会得到一个直接的答案。但是当使用“只读”属性时,你无法在CIA内部进行更改。例如,你不能打电话然后突然决定让金·卡戴珊成为局长,或者让帕丽斯·希尔顿成为总司令。
如果属性赋予了你“写”访问权限,那么即使你不在CIA内部,你也可以进行更改。否则,你唯一能做的就是阅读。
换句话说,访问器允许您查询或更改组织机构的内容,否则外部人员无法进入,具体取决于访问器是读访问器还是写访问器。
类中的对象可以轻松相互访问
对于类和您访问其中变量、属性和方法的能力,情况完全相同。希望有所帮助!如有任何问题,请随时提问,我希望能够澄清。
我也遇到了这个问题,并对此问题写了一个相当冗长的答案。虽然已经有一些很好的答案了,但是任何需要更多澄清的人,我希望我的答案能够帮助到你。
初始化方法
初始化允许您在创建实例的同时将数据设置给对象的实例,而不必在每次创建类的新实例时在代码中单独设置它们。
class Person
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
在上述代码中,我们使用初始化方法通过在 Initialize 中传递 Dennis 参数来设置名称“Denis”。如果我们想要在没有初始化方法的情况下设置名称,我们可以这样做: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
在以上代码中,我们通过调用attr_accessor setter方法使用person.name设置名称,而不是在对象初始化时设置值。
这两种方法都可以工作,但是初始化可以节省我们的时间和代码行数。
这是初始化的唯一工作。您不能将其作为方法调用。要获取实例对象的值,您需要使用getter和setter(attr_reader(get),attr_writer(set)和attr_accessor(both))。有关更多详细信息,请参见下面的内容。
Getter、Setter(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个状态属性呢?那么代码很快就会变得很冗长。
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的功能,可以帮助你省去一行代码。
我认为新的Ruby程序员(如我)感到困惑的部分是:
"为什么我不能一次性告诉实例它有任何给定的属性(例如名称),并为该属性赋值?"
更加普遍化,但这是我理解的方式:
假设:
class Person
end
我们还没有将“人”定义为可以拥有名称或其他属性的事物。
所以如果我们接着:
baby = Person.new
...并尝试为它们命名...
baby.name = "Ruth"
我们之所以会出现错误,是因为在 Rubyland 中,一个名为 Person 的对象类并不具备或关联于“名称”这个属性……还没有!
但是,我们可以使用前面提到的任何一种方法作为一种方式来表达,“Person 类的一个实例(baby
)现在可以拥有名为‘name’的属性,因此我们不仅有了一种语法上获取和设置该名称的方法,而且这样做也是有意义的。”
再次从稍微不同、更一般的角度回答这个问题,但我希望这能帮助下一个遇到 class Person 时的人。
git
与attr_accessor
没有关系。git
是一个版本控制软件,而attr_accessor
是 Ruby 中的一个方法。你可以在这里查看它的文档:http://ruby-doc.org/core-2.3.0/Module.html#method-i-attr_accessor。 - Uzbekjon