本帖最后由 RyanBern 于 2015-5-26 20:01 编辑
以'@'开头的变量,叫做实变量,它和一般临时变量不同的是,它永远是对象的一部分,只要对象存在,相应的实变量就会一直存在。
实变量使用时不需要声明,也就是说你想用什么实变量直接把它名字调出来就好了。未经赋初值的实变量的值是nil。
class A def initialize @x = 0 @y = 0 end def show p @x, @y end end a = A.new a.show # => 0, 0
class A
def initialize
@x = 0
@y = 0
end
def show
p @x, @y
end
end
a = A.new
a.show # => 0, 0
当然,这样定义的实变量只能在对象内部使用,也就是使用的地方必须在同一个类里面。换言之,如果在对象的外部访问实变量,是无法访问到的。
外界无法访问实变量有一定的好处,那就是可以保护数据,体现封装的安全性。但是也有很多时候,我们需要从对象外面访问相应的实变量。这个时候,我们就必须定义两个方法。
class A def initialize @x = 0 @y = 0 end def show p @x, @y end def x return @x end def x=(val) @x = val end end
class A
def initialize
@x = 0
@y = 0
end
def show
p @x, @y
end
def x
return @x
end
def x=(val)
@x = val
end
end
请注意我们新加入的两个方法,这两个方法是对实变量@x进行操作,其中,def x这个方法是返回@x本身的值,而def x=(val)这个方法是修改@x的值。有了这两个方法,我们就可以在对象外部调用了:
a = A.new p a.x #=> 0 a.x = 1 p a.x #=>1
a = A.new
p a.x #=> 0
a.x = 1
p a.x #=>1
请注意,原点运算符'.'的含义是调用该对象的方法,而不是访问对象@x的值或者修改@x的值,这点一定要注意。只不过,在这个例子里面,调用的两个方法'x'和'x='的作用恰恰是访问@x的值和改变@x的值而已。
不过,利用这种方法定义出来的对象,使用起来比较方便,又符合人们正常的认知习惯,所以,我们在使用实变量的时候,通常都会定义这两个方法,一个方法用于读取与该实变量有关的数据,也称之为get访问器,它的名字通常为实变量的名字(去掉'@');而另一个方法用于设置与该实变量有关的数据,也称之为set访问器,它的名字通常为实变量名字在加上'='符号。凡是定义了这两个方法(或者其中一个)而且作用又和某个实变量想关联的符号,我们称之为【属性】,【属性】是表示对象的某个方面的状态,这也比较符合我们认识世界的方法。
继续上面的例子,我们追加以下定义:
class A def y return @y end def y=(val) val = [[val, 0].max, 99].min @y = val end end
class A
def y
return @y
end
def y=(val)
val = [[val, 0].max, 99].min
@y = val
end
end
注意在这里我们定义的'y='方法,和上面的'x='方法稍有区别。接下来我们试一下:
a = A.new a.y = 10 p a.y #=>10 a.y = -1 p a.y #=> 0 a.y = 100 p a.y #=>99 a.instance_variable_set(:@y, -1) p a.y #=>-1
a = A.new
a.y = 10
p a.y #=>10
a.y = -1
p a.y #=> 0
a.y = 100
p a.y #=>99
a.instance_variable_set(:@y, -1)
p a.y #=>-1
我们看到,在这里,如果直接调用 a.y = 数值,那么@y的值并不是直接变成右面的数值,而是只能变为0~99中的数,这是因为'y='方法不再像'x='方法那样,简单改变@y的值,而是做了比较复杂的工作。而最后那一句a.instance_variable_set(:@y, -1)才是直接改变@y的数值,现在可以忽略这个地方。
最后,我想说一下下面这三个东西:
attr_accessor
attr_reader
attr_writer
这三个东西不知道有多少人会理解错误。先说说这三个家伙是什么吧,它们都是Module类的方法(如果不能理解什么是Module,那么要记住他们是【方法】),后面跟的参数是符号(Symbol)参数。它们的作用是根据给定的符号参数,来定义某些实例方法。
有一种理解是认为这三个东西是用于声明实变量的,这种理解方式是不对的。我们在一开始就说了,实变量不需要声明就可以使用,那么,何谈【声明实变量】这一说?
我们应该把这三个方法理解成【生成方法的方法】。
如果在class A下,写attr_accessor(:x)
这一句话是根据符号':x'生成两个方法,'x'和'x=',而生成的这两个方法的方法体,就是下面这样子:
def x return @x end def x=(val) @x = val end
def x
return @x
end
def x=(val)
@x = val
end
这不就是我们刚才第一遍给A类加方法的代码吗?对,attr_accessor(:x)的含义就是上面那几行代码。它为实变量@x提供了最基本也是最初等的get/set访问器。所以,当实变量较多而又需要外部引用的时候,用一个attr_accessor方法,就可以同时定义两个方法,代码是不是很简洁呢?而attr_reader方法,只定义了get访问器;attr_writer方法,只定义了set访问器,所以在使用的时候要根据需求,虽然attr_accessor定义的方法是两个,但是也不能什么实变量都用吧。
至于@后面跟中文字符的实变量,应该尽量避免,虽然它们所起的作用和正常的实变量没什么区别。 |