Difference between @instance
I Just started learning ruby and I don't see the difference between an @instace_variable
and an attribute declared using attr_accessor
.
What is the difference between the following two classes:
class MyClass
@variable1
end
and
class MyClass
attr_accessor :variable1
end
I searched lot of tutorials online and everybody uses different notation, Does it have to do anything with the ruby version? I also searched few old threads in StackOverflow
What is attr_accessor in Ruby?
What's the Difference Between These Two Ruby Class Initialization Definitions?
But still I am not able to figure out what is the best way to use.
An instance variable is not visible outside the object it is in; but when you create an attr_accessor
, it creates an instance variable and also makes it visible (and editable) outside the object.
Example with instance variable (not attr_accessor
)
class MyClass
def initialize
@greeting = "hello"
end
end
m = MyClass.new
m.greeting #results in the following error:
#NoMethodError: undefined method `greeting' for #<MyClass:0x007f9e5109c058 @greeting="hello">
Example using attr_accessor
:
class MyClass
attr_accessor :greeting
def initialize
@greeting = "hello"
end
end
m2 = MyClass.new
m2.greeting = "bonjour" # <-- set the @greeting variable from outside the object
m2.greeting #=> "bonjour" <-- didn't blow up as attr_accessor makes the variable accessible from outside the object
Hope that makes it clear.
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.
attr_accesor
gives you methods to read and write the instance variables. Instance variables are deasigned to be hidden from outside world so to communicate with them we should have attr _ibute accesor methods.
下一篇: @instance之间的区别