Instance variables 实例变量
As the name suggests,
instance variables are variables bound to class instances and its scope. Whereas local variables exist in one scope only, instance variables are carried by the instance/object of the class. The difference between local variables and instance variables is that the latter always start with
1 ‘@’. Whether or not the letter after that is uppercase or lowercase doesn’t matter.
实例变量,顾名思义,就是专用于实例的变量。
实例变量用来存储实例的某一个属性,或者说状态,我们来看下面的这个例子:
Ruby:
class NewClass
def initialize
@age = 10
end
def print_age
print @age
end
end
var = NewClass.new
# var now carries around the @age variable internally.
var.print_age #=> 10
# 在这个例子中,首先通过NewClass.new创建了一个NewClass的实例,
# 因为存在initialize方法,所以会立即调用这个方法,
# 在这个方法中,定义了一个实例变量@age,并且它的值是10,
# 接着,将这个实例和var联系了起来,
# 然后,对var调用print_age(打印年龄)方法,这个方法会打印出@age。
#
# 从这个例子中,我们可以发现,定义实例变量需要在变量名前加一个@。
# 并且,因为实例变量是针对于实例的,所以每一个实例都会有这个实例变量,
# 只要实例存在,实例变量就存在。
If you were to try this with local variables (without the @), it would perform age = 10 in def initialize, but then that method ends and the variable is gone again. Then calling print_age would try to access a non-existent variable, because there’s no local variable defined in print_age called age.
在上面的例子中,如果你不使用实例变量,而是使用局部变量的话,也就是age = 10,那么在初始化方法结束之后,这个变量没有了,你无法在print_age中调用age。
你也可以用作用域来理解,初始化方法的作用域和print_age方法的作用域是独立不互通的,所以它们之间的局部变量不能互相访问,而实例变量就可以在同一个类中的不同方法之间直接访问。
This is solved by using instance variables. These variables exist as long as the object they’re in exists. We can’t directly access this variable from outside of the class though, nor on the object itself (var). You have to be
in the class to manipulate instance variables. For this you need to create
helper methods, methods that allow you to read and write to the variable from the outside. This is pretty basic:
实例变量虽然可以在同一个类中的不同方法之间直接访问,但是却不能在这个类之外直接进行访问,你只能在这个类之内操纵实例变量。
为了能在外部访问实例变量,我们需要创建一些辅助方法来帮助我们,请看下面的这个例子:
Ruby:
class NewClass
def initialize
@age = 10
end
def get_age
return @age
end
def set_age(new_value)
@age = new_value
end
end
var = NewClass.new
print var.get_age #=> 10
var.set_age(17)
print var.get_age #=> 17
var.set_age(10)
print var.get_age #=> 10
# 在这个例子中,我们就可以在类的外部通过get_age(得到年龄)来访问@age,
# 通过set_age(设置年龄)重新设置@age的值。
# 也就是说,get_age和set_age就是辅助方法,一个用来访问值,一个用来设置值
But that’s convoluted and annoying to do for
every single instance variable (if it’s a big class, you can easily have dozens of instance variables). That’s why we can create
getter and
setter methods. Getter methods are basically just methods with the same name as the instance variable, which return the value of said instance variable (exactly the same as get_age but with a different name). Setters are a bit different though. Rather than set_age(10), setter methods allow you to use assignment with = to call the method (yes, assignment is also a method!)
但是,为每一个实例变量都添加这样的两个方法是非常烦人的。
所以我们创造了获取器和设置器方法。
获取器是一个和变量的名字相同的方法,而设置器是一个在变量的名字后面加一个“=”的名字的方法。
假如说有个实例变量是@age,那获取器就是age,设置器就是age=,注意,这个“=”是设置器名字的一部分。
First to demonstrate the getter method:
首先我们来看获取器的例子:
Ruby:
class NewClass
def initialize
@age = 10
end
# Getter
def age
return @age
end
end
p NewClass.new.age #=> 10
Next comes the setter method:
接着我们来看设置器的例子:
Ruby:
class NewClass
def initialize
@age = 10
end
# Getter
def age
return @age
end
# Setter
def age=(new_value)
@age = new_value
end
# 通过传递new_value(新的值)来设置@age的值。
end
var = NewClass.new
p var.age #=> 10
var.age = 17
# 注意,这里其实是age=(17),前面其实也说过,参数的括号是可以省略的,
# 所以可以写成age=17,接着你再加一些空格,就变成了age = 17。
# 也就是说其实是对var调用设置器方法,这里的17是传递的参数。
p var.age #=> 17
var.age=(10) # Identical to normal assignment
p var.age #=> 10
# You can even perform mathematical functions with it:
var.age **= 2
# 这里其实是var.age= age * age,也就是说这里其实是结合使用了
# 获取器和设置器。
p var.age #=> 100
So when you create a method with an equal sign = at the end of the method name, that method will be treated as an assignment method, with =.
There’s really no need for getter and setter methods, unless you want the instance variable to BE public and to be used outside of the class itself.
These getter and setter methods can be very useful, but it’s a lot to write if you have a lot of instance variables. That’s why there are shortcuts for these getters and setters:
attr_reader: This is the getter method. Equal to def age in the previous examples.
attr_writer: This is the setter method. Equal to def age=(v) in the previous examples.
attr_accessor: This is both the getter
and the setter method. Equal to def age and def age=(v) in the previous examples.
因为获取器和设置器实在是太基础也太重要了,所以我们又创造了更加简便的添加获取器和设置器的方法。
添加获取器,我们只需要写attr_reader(读取器),添加设置器,我们只需要写attr_writer(写入器),而如果你写attr_accessor(访问器)的话,就是同时添加了获取器和设置器。
attr also means Attribute. Attribute reader (getter), Attribute writer (setter), Attribute accessor (getter + setter).
这里的“attr”其实是attribute(属性)的简写,attr_reader就是属性的读取器,attr_writer就是属性的写入器,attr_accessor就是属性的访问器,即读取器+写入器。
To use these shortcuts, you choose the keyword followed by a colon :, followed by the name of the instance variable. When used, it will basically turn into the proper method(s) in the order you wrote them. This means that you can overwrite the functionality later, if you want, just by typing out the method and implementing your desired functionality (just like a normal method).
那么具体该怎么做呢?
我们来看下面的这个例子:
Ruby:
class NewClass
# They're usually at the top, along with constants
attr_accessor :age
# 也就是说,我们通过“attr_accessor :xxx”这样的格式,就可以
# 快速创建@xxx变量的读取器和设置器。
def initialize
@age = 10
end
end
var = NewClass.new
print var.age #=> 10
var.age = 17
print var.age #=> 17