accessor in Ruby?

I am having a hard time understanding attr_accessor in Ruby. Can someone explain this to me?


Let's say you have a class Person .

class Person
end

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

Obviously we never defined method name . Let's do that.

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

Aha, we can read the name, but that doesn't mean we can assign the name. Those are two different methods. The former is called reader and latter is called writer. We didn't create the writer yet so let's do that.

class Person
  def name
    @name
  end

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

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

Awesome. Now we can write and read instance variable @name using reader and writer methods. Except, this is done so frequently, why waste time writing these methods every time? We can do it easier.

class Person
  attr_reader :name
  attr_writer :name
end

Even this can get repetitive. When you want both reader and writer just use accessor!

class Person
  attr_accessor :name
end

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

Works the same way! And guess what: the instance variable @name in our person object will be set just like when we did it manually, so you can use it in other methods.

class Person
  attr_accessor :name

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

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

That's it. In order to understand how attr_reader , attr_writer , and attr_accessor methods actually generate methods for you, read other answers, books, ruby docs.


attr_accessor is just a method. (The link should provide more insight with how it works - look at the pairs of methods generated, and a tutorial should show you how to use it.)

The trick is that class is not a definition in Ruby (it is "just a definition" in languages like C++ and Java), but it is an expression that evaluates. It is during this evaluation when the attr_accessor method is invoked which in turn modifies the current class - remember the implicit receiver: self.attr_accessor , where self is the "open" class object at this point.

The need for attr_accessor and friends, is, well:

  • Ruby, like Smalltalk, does not allow instance variables to be accessed outside of methods1 for that object. That is, instance variables cannot be accessed in the xy form as is common in say, Java or even Python. In Ruby y is always taken as a message to send (or "method to call"). Thus the attr_* methods create wrappers which proxy the instance @variable access through dynamically created methods.

  • Boilerplate sucks

  • Hope this clarifies some of the little details. Happy coding.


    1 This isn't strictly true and there are some "techniques" around this, but there is no syntax support for "public instance variable" access.


    attr_accessor is (as @pst stated) just a method. What it does is create more methods for you.

    So this code here:

    class Foo
      attr_accessor :bar
    end
    

    is equivalent to this code:

    class Foo
      def bar
        @bar
      end
      def bar=( new_value )
        @bar = new_value
      end
    end
    

    You can write this sort of method yourself in 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
    
    链接地址: http://www.djcxy.com/p/646.html

    上一篇: 为什么在Ruby中`拯救Exception => e`是不好的风格?

    下一篇: Ruby中的访问器?