Ruby中的attr_accessor是什么?

What is attr_accessor in Ruby?

我很难理解Ruby中的attr_accessor。有人能给我解释一下吗?


假设您有一个类Person

1
2
3
4
5
class Person
end

person = Person.new
person.name # => no method error

显然,我们从未定义过方法name。让我们这样做。

1
2
3
4
5
6
7
8
9
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

啊哈,我们可以读名字,但这并不意味着我们可以指定名字。这是两种不同的方法。前者被称为读者,后者被称为作家。我们还没有创建作者,所以让我们开始吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
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。但是,这样做太频繁了,为什么每次都浪费时间写这些方法呢?我们可以做得更容易。

1
2
3
4
class Person
  attr_reader :name
  attr_writer :name
end

即使这样也会重复。当你同时需要读写器时,只需要使用存取器!

1
2
3
4
5
6
7
class Person
  attr_accessor :name
end

person = Person.new
person.name ="Dennis"
person.name # =>"Dennis"

工作原理相同!猜猜看:我们的Person对象中的实例变量@name的设置与我们手动设置时的设置相同,所以您可以在其他方法中使用它。

1
2
3
4
5
6
7
8
9
10
11
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访问器只是一种方法。(链接应该提供关于它如何工作的更多信息-查看生成的方法对,教程应该向您展示如何使用它。)

诀窍在于,EDCOX1 0Ω不是Ruby中的一个定义(它是C++语言和Java语言中的"一个定义"),但它是一个求值的表达式。在这个评估过程中,调用了attr_accessor方法,该方法反过来修改了当前类—记住隐式接收器:self.attr_accessor,其中self是此时的"开放"类对象。

attr_accessor和朋友的需要是:

  • Ruby和Smalltalk一样,不允许在该对象的方法1之外访问实例变量。也就是说,实例变量不能在EDCOX1的5形式中访问,这在Java、甚至Python中都是常见的。在Rubyy中,始终将其作为要发送的消息(或"调用方法")。因此,attr_*方法创建包装器,通过动态创建的方法代理实例@variable访问。

  • 样板吸盘

  • 希望这能澄清一些小细节。快乐编码。

    1这并不是严格意义上的事实,在这方面有一些"技术",但是没有对"公共实例变量"访问的语法支持。


    attr_accessor只是一种方法(如@pst所述)。它所做的是为您创建更多的方法。

    所以这里的代码是:

    1
    2
    3
    class Foo
      attr_accessor :bar
    end

    等同于此代码:

    1
    2
    3
    4
    5
    6
    7
    8
    class Foo
      def bar
        @bar
      end
      def bar=( new_value )
        @bar = new_value
      end
    end

    您可以自己用Ruby编写这种方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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非常简单:

    1
    attr_accessor :foo

    是一个快捷方式:

    1
    2
    3
    4
    5
    6
    7
    def foo=(val)
      @foo = val
    end

    def foo
      @foo
    end

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


    基本上,它们伪造了Ruby没有的可公开访问的数据属性。


    它只是一个为实例变量定义getter和setter方法的方法。一个示例实现是:

    1
    2
    3
    4
    5
    6
    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


    如果您熟悉OOP概念,那么您必须熟悉getter和setter方法。attr-accessor在ruby中也做同样的事情。

    一般的打手和二传手

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Person
      def name
        @name
      end

      def name=(str)
        @name = str
      end
    end

    person = Person.new
    person.name = 'Eshaan'
    person.name # =>"Eshaan"

    设定法

    1
    2
    3
    def name=(val)
      @name = val
    end

    吸气剂法

    1
    2
    3
    def name
      @name
    end

    Ruby中的getter和setter方法

    1
    2
    3
    4
    5
    6
    7
    class Person
      attr_accessor :name
    end

    person = Person.new
    person.name ="Eshaan"
    person.name # =>"Eshaan"


    不带任何代码的简单解释

    以上大多数答案都使用代码。这个解释试图通过一个类比/故事来回答它,而不使用任何:

    外部各方无法获取CIA内部机密

    • 让我们想象一个真正秘密的地方:中央情报局。除了中情局内部的人,没有人知道中情局发生了什么。换言之,外部人员无法访问中情局的任何信息。但是,由于拥有一个完全保密的组织是不好的,因此某些信息可以提供给外部世界——当然,只有中央情报局想让每个人都知道的事情:例如中央情报局局长,这个部门与所有其他政府部门相比有多环保等等。其他信息:e谁是它在伊拉克或阿富汗的秘密特工——这些事情在未来150年内可能仍然是秘密。

    • 如果你在中央情报局之外,你只能访问它向公众提供的信息。或者使用中情局的说法,你只能访问"清除"的信息。

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

    读写属性的含义:

    • 在CIA的情况下,大多数属性是"只读"的。这意味着如果你是中情局外部的一方,你可以问:"谁是中情局局长?"你会得到一个直接的答案。但是你不能用"只读"属性来改变中情局。例如,你不能打电话,突然决定你想让金·卡戴珊担任导演,或者你想让帕里斯·希尔顿担任总司令。

    • 如果属性赋予您"写"访问权,那么您可以根据需要进行更改,即使您在外面也可以。否则,你唯一能做的就是阅读。

      换句话说,访问器允许您向不允许外部人员进入的组织进行查询或更改,这取决于访问器是读访问器还是写访问器。

    类中的对象可以轻松地访问彼此

    • 另一方面,如果你已经进入了中央情报局,那么你可以很容易地打电话给你在喀布尔的中央情报局特工,因为这个信息很容易获取,因为你已经进入了中央情报局。但是,如果你在中情局之外,你将无法获得访问权:你将无法知道他们是谁(读访问权),也无法改变他们的任务(写访问权)。

    类和访问其中变量、属性和方法的能力完全相同。嗯!任何问题,请提问,我希望我能澄清。


    我也面临这个问题,对这个问题写了一个有点冗长的回答。关于这个问题已经有了一些很好的答案,但是任何人想要更多的澄清,我希望我的答案能有所帮助。

    初始化方法

    初始化允许您在创建实例时将数据设置为对象的实例,而不必在每次创建类的新实例时在代码中单独一行设置数据。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Person
      attr_accessor :name

      def initialize(name)
        @name = name
      end


      def greeting
       "Hello #{@name}"
      end
    end

    person = Person.new("Denis")
    puts person.greeting

    在上面的代码中,我们使用initialize方法通过在initialize中通过参数传递dennis来设置名称"denis"。如果我们想在不使用初始化方法的情况下设置名称,可以这样做:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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访问器setter方法来设置名称,而不是在初始化对象时设置值。

    这两种"方法"都可以完成这项工作,但初始化可以节省我们的时间和代码行。

    这是初始化的唯一工作。不能将初始化调用为方法。要实际获取实例对象的值,需要使用getter和setter(attr_reader(get)、attr_writer(set)和attr_accessor(both))。有关这些内容的更多详细信息,请参见下文。

    getter、setters(attr_reader、attr_writer、attr_accessor)

    getters,attr_reader:getter的全部目的是返回特定实例变量的值。请访问下面的示例代码,了解有关此问题的详细信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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"项的实例上调用方法"itemu name"和"quantity"。"puts example.item_name"和"example.quantity"将返回(或"get")传递到"example"中的参数值,并将其显示在屏幕上。

    幸运的是,在Ruby中,有一个固有的方法可以让我们更简洁地编写代码:attr_reader方法。见下面的代码;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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方法完全相同。下面我根据我的理解来解释这些差异;

    如前所述,初始化方法允许您在对象创建时设置对象实例的值。

    但是,如果您希望稍后在创建实例之后设置这些值,或者在初始化之后更改这些值,该怎么办?这将是一个使用setter方法的场景。这就是区别。最初使用attr-writer方法时,不必"设置"特定状态。

    下面的代码是一个使用setter方法声明该item类实例的值item_name的示例。请注意,我们继续使用getter方法attr_reader,这样我们就可以获取值并将它们打印到屏幕上,以防您想自己测试代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Item

    attr_reader :item_name

      def item_name=(str)
        @item_name = (str)
      end

    end

    下面的代码是一个使用attr_writer再次缩短代码并节省时间的示例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Item

    attr_reader :item_name
    attr_writer :item_name

    end

    item = Item.new
    puts item.item_name ="TV"

    下面的代码重申了上面的初始化示例,其中我们使用initialize在创建时设置项名称的对象值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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的功能,为您多保存一行代码。


    我认为让新红人/程序员(和我一样)感到困惑的部分原因是:

    "为什么我不能告诉实例它有任何给定的属性(例如名称),并在一个Swoop中为该属性赋予一个值?"

    稍微广义一点,但这就是它对我的点击方式:

    鉴于:

    1
    2
    class Person
    end

    我们还没有将人定义为可以有名字或任何其他属性的人。

    所以如果我们当时:

    1
    baby = Person.new

    …给他们起个名字…

    1
    baby.name ="Ruth"

    我们会得到一个错误,因为在Rubyland中,对象的一个人类不是与"名称"相关联或具有"名称"能力的东西…但是!

    但是我们可以使用任何给定的方法(参见前面的答案)来表示:"一个Person类的实例(baby现在可以有一个名为‘name’的属性,因此我们不仅有一个获取和设置该名称的语法方法,而且这样做是有意义的。"

    再一次,从一个稍微不同和更一般的角度来回答这个问题,但是我希望这能帮助下一个班上的人找到解决这个问题的方法。


    简单地说,它将为类定义一个setter和getter。

    注意

    1
    2
    3
    4
    5
    6
    7
    8
    9
    attr_reader :v is equivalant to
    def v
      @v
    end

    attr_writer :v is equivalant to
    def v=(value)
      @v=value
    end

    所以

    1
    2
    attr_accessor :v which means
    attr_reader :v; attr_writer :v

    等价于为类定义setter和getter。


    简单地说,attr-accessor为指定的属性创建gettersetter方法


    EN is to another方式了解人物eliminates队列超时是很attr_accessorEN误差模式。P></

    实例:P></

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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

    方法:the following are availableP></

    1
    2
    3
    4
    $ bankie = BankAccout.new("Iggy")
    $ bankie
    $ bankie.deposit(100)
    $ bankie.withdraw(5)

    方法:throws the following errorP></

    1
    2
    $ bankie.owner     #undefined method `owner'...
    $ bankie.balance   #undefined method `balance'...

    ownerbalanceare not,but an technically,方法,属性。does not have def ownerBankAccount类和def balance。if it does,那么你可以使用以下命令:二。但这些方法是双T *。不管一个人多,as if You can access属性访问方法attr_accessor离开你!因此,attr_accessorthe word!。属性。访问器。你会喜欢它accesses属性的访问方法。P></

    attr_accessor :balance, :ownerallows增你读和写balanceowner"和法"。现在你可以使用最后的方法2。P></

    1
    2
    $ bankie.balance
    $ bankie.owner

    定义此模块的命名属性,其中名称为symbol.id2name,创建一个实例变量(@name)和相应的访问方法来读取它。还创建一个名为name=的方法来设置属性。

    1
    2
    3
    4
    module Mod
      attr_accessor(:one, :two)
    end
    Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]

    为了总结一个属性访问器,aka attr_访问器为您提供了两个自由方法。

    和Java一样,它们被称为吸气剂和定位器。

    很多答案都有很好的例子,所以我只想简单一点。

    第二属性

    { TysAt=

    在旧Ruby文档中,散列标记表示一个方法。它还可以包含类名前缀…MyClass我的方法


    我对鲁比还不太熟悉,只能理解下面的奇怪之处。将来可能会帮助别人。最后,如前所述,其中两个函数(def myvar,def myvar=)都隐式获取以访问@myvar,但这些方法可以被本地声明覆盖。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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


    访问方法和属性

    属性类零件是在accessed that can be from the object。known as they are many other programming languages属性中。他们是accessible by using the values"点的位置,如"在_ name.attribute _ name对象。于一些其他语言Python和Ruby,does not allow to be accessed元/ directly from the外面的对象。P></

    1
    2
    3
    4
    5
    6
    7
    8
    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>

    在the above example is an instance,C级(对象)of the SRC。我们unsuccessfully tried to read the value of the from the instance变量对象车轮外面。什么发生在attempted to that is named红宝石轮呼叫法在C对象定义的方法,但我不这样。总之,_ name.attribute _ tries to name对象在方法呼叫_ name属性在对象命名。Access to the value of the轮变"from the need to an instance,我们实施"订单模式,which will method name,value of variable that when the归我。这就是所谓的安访问器方法。通用设计在the context to the一切照旧的方式接入,从外面安审对象变量的访问器方法is to the also known as实施"订单,getter和setter方法。在allows the value of a variable吸气剂在类定义在"to be read from the setter和allows en to be written from the外面。P></

    在the following example,we have added to the吸气剂和setter方法的SRC级变量从"the the轮访问对象。"This is not the Way of defining getters红宝石"和制定者;serves only to吸气剂和setter方法给了我。P></

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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

    above the example is similar工厂和队列创建和setter commonly used to other languages吸气剂的方法中。不管一个人多简单的内部通道,提供给在红宝石的方法:建立在这三个属性和属性_读者,作家_ _ acessor属性。the method属性变量使安审_阅读器可读写属性_ from the外面,让恩布尔属性可写,可读和可写的_ acessor让它。P></

    rewritten above the example can be like this。P></

    1
    2
    3
    4
    5
    6
    7
    class Car
      attr_accessor :wheels
    end

    f = Car.new
    f.wheels = 4
    f.wheels  # Output: => 4

    在the above the example,可读可写属性和轮子will be the对象从外面。如果_ instead of attr属性访问器,我不知道它会好的_阅读器,只读存储器。if we used _作家属性,它只会好写。的方法和getters are not那些三者在themselves but when they called,吸气剂和setter方法创建的,为美国。他们的方法,是其他方法所产生的dynamically(以编程方式);这就是所谓的元编程。P></

    example,the first(周)which does not employ红宝石- S在新建好的方法,只有当用should the additional is required队列在吸气和setter方法。在五月的setter method for instance,need to some计算验证,鉴于我之前在assigning value to an instance变量。P></

    EN is possible to access(读和写)元对象的外审,from the by using the审,审_ get和_ _变量变量在_集建立方法。不管一个人多,this is rarely justifiable和usually坏主意,as to wreak bypassing胶囊成囊的种类tends of破坏。P></


    嗯。很多好答案。这是我的几美分。

    • attr_accessor是一种简单的方法,它帮助我们清洁(干燥)重复的getter and setter方法。

    • 这样我们就可以更专注于编写业务逻辑,而不必担心setter和getter。


    attr_访问器的主要功能是从其他文件访问数据。所以你通常会有attr_reader或者attr_writer,但好消息是Ruby让你把这两者和attr_accessor结合在一起。我认为这是我的去,因为它是更全面或多才多艺的方法。另外,请注意,在Rails中,这是被消除的,因为它在后端为您做了这件事。换言之,你最好使用ATTR访问器,而不是其他两个访问器,因为你不必担心具体的问题,访问器可以覆盖所有的问题。我知道这是一个更一般的解释,但它帮助我作为一个初学者。

    希望这有帮助!