一。基础知识:实例变量的特殊性:
ruby中的实例变量,是在实例变量的表中去寻找的。这样,一个@name在没有定义的时候,寻找的结果是nil,而不是异常。
但是,如果没有定义类变量@@buffer,则会抛出异常。
class MAttrAccessorTest #ok~ puts @name #=>nil #ERROR puts @@buffer #=>uninitialized class variable @@aaa in MAttrAccessorTest (NameError) end
二。attr_accessor,自动给实例变量加入get set 方法
例子:
class AttrAccessorTest attr_accessor :name, :age #get method def love @love end #set method def love=(love) @love = love end end
输出:
user = AttrAccessorTest.new
user.name = "June"
puts user.inspect
puts user.age #=>nil
puts user.inspect
user.age = 29
puts user.age
puts user.inspect
三。mattr_accessor :user_buffer
这个方法会在module中定义一个类变量:@@user_buffer;
同时定义对这个类变量的get,set方法,注意是实例方法。
这样,当包含这个模块的时候,会有@@user_buffer这个类变量,和get/set方法。
因为类变量是给所有实例共享的,所以某个实例修改这个类变量后,其他实例访问到的类变量也发生变化了。
例子:
module MAttrAccessorTest mattr_accessor :user_buffer #这个时候这里不会报错了!!! puts @@user_buffer end class AttrAccessorTest include MAttrAccessorTest end user1 = AttrAccessorTest.new user2 = AttrAccessorTest.new puts "user1.user_buffer = #{user1.user_buffer.inspect}" puts "user2.user_buffer = #{user2.user_buffer.inspect}" user1.user_buffer = [] user1.user_buffer << "Fantaxy" puts "user1.user_buffer = #{user1.user_buffer.inspect}" puts "user2.user_buffer = #{user2.user_buffer.inspect}" user2.user_buffer << "June" puts "user1.user_buffer = #{user1.user_buffer.inspect}" puts "user2.user_buffer = #{user2.user_buffer.inspect}"
输出:
nil
user1.user_buffer = nil
user2.user_buffer = nil
user1.user_buffer = ["Fantaxy"]
user2.user_buffer = ["Fantaxy"]
user1.user_buffer = ["Fantaxy", "June"]
user2.user_buffer = ["Fantaxy", "June"]
四。cattr_accessor :user_buffer
同mattr_accessor,只不过是使用在了类中。
例子:
class AttrAccessorTest mattr_accessor :user_buffer #这个时候这里不会报错了!!! puts @@user_buffer end user1 = AttrAccessorTest.new user2 = AttrAccessorTest.new puts "user1.user_buffer = #{user1.user_buffer.inspect}" puts "user2.user_buffer = #{user2.user_buffer.inspect}" user1.user_buffer = [] user1.user_buffer << "Fantaxy" puts "user1.user_buffer = #{user1.user_buffer.inspect}" puts "user2.user_buffer = #{user2.user_buffer.inspect}" user2.user_buffer << "June" puts "user1.user_buffer = #{user1.user_buffer.inspect}" puts "user2.user_buffer = #{user2.user_buffer.inspect}" 输出: nil user1.user_buffer = nil user2.user_buffer = nil user1.user_buffer = ["Fantaxy"] user2.user_buffer = ["Fantaxy"] user1.user_buffer = ["Fantaxy", "June"] user2.user_buffer = ["Fantaxy", "June"]
输出:
nil
user1.user_buffer = nil
user2.user_buffer = nil
user1.user_buffer = ["Fantaxy"]
user2.user_buffer = ["Fantaxy"]
user1.user_buffer = ["Fantaxy", "June"]
user2.user_buffer = ["Fantaxy", "June"]
五。class_inheritable_accessor
不要使用这个为好:
#1,貌似有bug
#2,晦涩且复杂度高,容易出错
class Parent class_inheritable_accessor :name, :age self.name = "Human" #注意这里必须先赋值,否则就不灵了哦,请对比:superclass_delegating_accessor self.age = "2000_000 years" def to_s "name = #{name}, age = #{age}" end end class Child < Parent end parent = Parent.new puts "parent: #{parent}" parent.name = "JRuby Programmer" parent.age = "3 years ago" puts "parent: #{parent}" puts "----" child1 = Child.new child2 = Child.new puts "child1: #{child1}" puts "child2: #{child2}" puts "----" child1.name = "Programmer" child1.age = "100 years ago" puts "child1.name = #{child1.name}, child1.age = #{child1.age}" puts "child2.name = #{child2.name}, child2.age = #{child2.age}" puts "----" child2.name = "Java Programmer" child2.age = "From 1991" puts "child1.name = #{child1.name}, child1.age = #{child1.age}" puts "child2.name = #{child2.name}, child2.age = #{child2.age}"
六。superclass_delegating_accessor
这个也被rails3废弃了。
附:
mattr_accessor和cattr_accessor源码简析:
#1 在Class中加入了实例方法:mattr_accessor/cattr_accessor
#2 这些实例方法对于每个类来说,属于类方法
#3 这些类方法能在类的作用域内使用,格式如:mattr_accessor :user_buffer, :visit_buffer
#4 这些方法本身使用class_eval/module_eval往类中加入实例方法,即get/set方法
#5 这些get/set方法操作的变量都是类变量,能被其所有类和实例共享
另外:
如果使用:instance_writer => false 则表示关闭实例对类变量的写权限
例子: mattr_accessor :user_buffer, :instance_writer => false
+
+
+
*
+
+
+