Difference between @instance_variable and attr_accessor

前端 未结 6 1821
日久生厌
日久生厌 2020-12-13 00:28

I Just started learning ruby and I don\'t see the difference between an @instace_variable and an attribute declared using attr_accessor.

Wh

6条回答
  •  情歌与酒
    2020-12-13 01:12

    Instance variables are not visible outside of the class.

    class MyClass
      def initialize
        @message = "Hello"
      end
    end
    
    msg = MyClass.new
    @message
    #==> nil   # This @message belongs to the global object, not msg
    msg.message
    #==> NoMethodError: undefined method `message'
    msg.@message
    #==> SyntaxError: syntax error, unexpected tIVAR
    

    Now, you can always do this:

    msg.instance_eval { @message }
    

    But that's awkward and cheatish. Poking around someone else's class may be educational, but your client code shouldn't be doing it if you want to get reliable results. On the flip side, if you want clients to be able to see those values, don't make them use instance_eval; instead, define a method that does the trick:

    class MyClass
      def message 
        return @message
      end
    end
    msg.message
    # ==> "Hello"
    

    Because you so often want to do that, Ruby provides a shortcut to make it easier. The code below has exactly the same result as the code above:

    class MyClass
      attr_reader :message
    end
    

    That's not a new type of variable; it's just a shorthand way to define the method. You can look at msg.methods and see that it now has a message method.

    Now, what if you want to allow outsiders to not only see the value of an instance variable, but change it, too? For that, you have to define a different method for assignment, with a = in the name:

    class MyClass
      def message=(new_value)
        @message = new_value
      end
    end
    msg.message = "Good-bye"
    msg.message
    # ==> "Good-bye"
    

    Note that the assignment operators are semi-magical here; even though there's a space between msg.message and =, Ruby still knows to call the message= method. Combination operators like += and so on will trigger calls to the method as well.

    Again, this is a common design, so Ruby provides a shortcut for it, too:

    class MyClass
      attr_writer :message
    end
    

    Now, if you use attr_writer by itself, you get an attribute that can be modified, but not seen. There are some odd use cases where that's what you want, but most of the time, if you are going to let outsiders modify the variable, you want them to be able to read it, too. Rather than having to declare both an attr_reader and an attr_writer, you can declare both at once like so:

    class MyClass
      attr_accessor :message
    end
    

    Again, this is just a shortcut for defining methods that let you get at the instance variable from outside of the class.

提交回复
热议问题