tutorial - ruby语法




Ruby中的attr_accessor是什么? (12)

我很难理解Ruby中的attr_accessor 。 谁可以给我解释一下这个?


属性和访问器方法

属性是可以从对象外部访问的类组件。 它们被称为许多其他编程语言的属性。 它们的值可以通过使用“点符号”来访问,如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类的一个实例(对象)。 我们尝试从对象外部读取wheels实例变量的值,但尝试失败。 发生了什么事是Ruby尝试在c对象内调用一个名为wheels的方法,但是没有定义这样的方法。 简而言之,object_name.attribute_name会尝试在对象内调用名为attribute_name的方法。 要从外部访问wheels变量的值,我们需要通过该名称实现一个实例方法,该方法在调用时会返回该变量的值。 这就是所谓的访问方法。 在一般的编程环境中,从对象外部访问实例变量的常用方法是实现访问器方法,也称为getter和setter方法。 getter允许从外部读取类中定义的变量的值,并且setter允许从外部写入该值。

在以下示例中,我们将getter和setter方法添加到Car类以从对象外部访问车轮变量。 这不是定义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_accessor,我们使用attr_reader,它将是只读的。 如果我们使用attr_writer,它将是只写的。 这三种方法本身不是获取者和设置者,而是在被调用时为我们创建getter和setter方法。 它们是动态(编程)生成其他方法的方法; 这就是所谓的元编程。

第一个(较长)的例子,不使用Ruby的内置方法,只能在getter和setter方法需要额外的代码时使用。 例如,在为实例变量赋值之前,setter方法可能需要验证数据或进行一些计算。

通过使用instance_variable_get和instance_variable_set内置方法,可以从对象外部访问(读取和写入)实例变量。 然而,这很少合理,通常是一个坏主意,因为绕过封装往往会带来各种各样的破坏。


attr_accessor 只是一种方法 。 (该链接应该提供更多关于它如何工作的信息 - 查看生成的方法对,并且教程应该告诉你如何使用它。)

诀窍是, class 不是 Ruby中的定义 (它仅仅是C ++和Java等语言中的一个定义),但它是一个表达式 。 正是在这个评估过程中,调用了attr_accessor方法,这又调整了当前类 - 记住隐式接收方: self.attr_accessor ,其中self是此时的“open”类对象。

attr_accessor和朋友的需求,很好:

  1. Ruby和Smalltalk一样,不允许在该对象的方法1之外访问实例变量。 也就是说,实例变量无法以xy格式访问,就像在Java或甚至Python中常见的那样。 在Ruby中, y总是作为一个消息发送(或“调用方法”)。 因此, attr_*方法通过动态创建的方法创建代理实例@variable访问的包装器。

  2. 锅板很烂

希望能够澄清一些小的细节。 快乐的编码。

1这并非严格意义上的,这里有一些“技巧” ,但是没有对“公共实例变量”访问的语法支持。


attr_accessor非常简单:

attr_accessor :foo

是一个捷径:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

它只不过是一个对象的getter / setter


attr_accessor与其他文件的主要功能是从其他文件访问数据的功能。
所以你通常会有attr_reader或attr_writer,但好消息是Ruby允许你将这两者与attr_accessor结合在一起。 我认为这是我的方法,因为它更全面或多功能。 另外,请记住,在Rails中,这被淘汰,因为它在后端为你做。 换句话说:您最好使用attr_acessor而不是另外两个,因为您不必担心特定的问题,访问者会覆盖这一切。 我知道这更多的是一般性解释,但它帮助我成为初学者。

希望这有助于!


假设你有一个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 。 除此之外,经常这样做,为什么每次都浪费时间写这些方法呢? 我们可以做得更轻松。

class Person
  attr_reader :name
  attr_writer :name
end

即使这可能会重复。 当你想让读写器都使用accessor!

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_readerattr_writerattr_accessor方法如何为您生成方法,请阅读其他答案,书籍和ruby文档。


只需attr-accessor为指定的属性创建gettersetter方法


基本上他们伪造了公共可访问的数据属性,这是Ruby不具备的。


大多数上述答案使用代码。 此解释试图在不使用任何代码的情况下回答它:

通过类比解释

外部党派不能访问内部中央情报局的秘密

  • 让我们想象一个非常隐秘的地方:中央情报局。 除了中央情报局的人员外,没有人知道中央情报局正在发生什么。 换句话说,外部人不能访问CIA中的任何信息。 但是因为拥有一个完全秘密的组织并不是一件好事,某些信息可以提供给外部世界 - 只有中情局当然希望每个人都知道的事情:例如中情局局长,这个部门的环境友好程度如何所有其他政府部门等。其他信息:例如,谁是在伊拉克或阿富汗的秘密行动者 - 这些类型的事情可能在未来150年内保持秘密。

  • 如果你在CIA之外,你只能访问它提供给公众的信息。 或者使用CIA的说法,您只能访问“已清除”的信息。

  • 中央情报局希望提供给中央情报局以外的公众的信息称为: 属性。

读写属性的含义:

  • 在CIA的情况下,大多数属性是“只读”。 这意味着如果你是中央情报局外部的一方,你可以问: “中情局局长是谁?” 你会得到一个直接的答案。 但是,“只读”属性无法做到的是在CIA中进行更改。 例如,你不能打个电话,并突然决定你想让Kim Kardashian当导演,或者你希望Paris Hilton成为总司令。

  • 如果属性给了你“写入”权限,那么即使你在外面,你也可以做出改变。 否则,你唯一能做的就是阅读。

    换言之,访问者允许您向不允许外部人员进入的组织进行查询或进行更改,具体取决于访问者是读取还是写入访问者。

类内的对象可以轻松访问对方

  • 另一方面,如果你已经进入中央情报局,那么你可以轻松地打电话给你在喀布尔的中央情报局工作人员,并询问他下班后是否想与当地喀布尔的知情人一起喝啤酒。 但是如果你不在中央情报局,你根本就不会获得访问权限:你无法知道他们是谁(阅读权限),你将无法改变他们的使命(写入权限)。

与类完全相同的东西以及你访问变量,属性和方法的能力。 HTH! 如有任何问题,请询问我希望我能澄清。


它只是一个为实例变量定义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

总结一个属性访问器又名attr_accessor给你两个免费的方法。

就像在Java中一样,他们被称为getter和setter。

很多答案都显示了很好的例子,所以我只是简单介绍一下。

#the_attribute

#the_attribute =

在老红宝石文档中,哈希标签#意味着一种方法。 它也可以包含一个类名前缀... MyClass#my_method


我认为混淆Ruby的新手/程序员(像我自己)的一部分是:

“为什么我不能告诉实例它有任何给定的属性(例如名称),并且一次性给这个属性赋值?”

有点更一般化,但这是它为我点击的方式:

鉴于:

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'...

ownerbalance在技​​术上不是一种方法 ,而是一种属性。 BankAccount类没有def ownerdef balance 。 如果是这样,那么你可以使用下面的两个命令。 但是这两种方法都不存在。 但是,您可以像访问通过attr_accessor的方法一样访问属性! 因此这个词attr_accessor 。 属性。 访问。 它像访问一个方法一样访问属性。

添加attr_accessor :balance, :owner允许您读写balanceowner “方法”。 现在你可以使用最后2种方法。

$ bankie.balance
$ bankie.owner




ruby