[No000011]Ruby之attr_reader,attr_writer,attr_accessor理解&用法

(Ruby/Python/Perl)

  Ruby 语言与Python和Perl的一个很大区别,在于Ruby中,所有的实例变量都是在类中完全私有的,只能通过accessor 方法来进行变量访问,引用一段代码来说明具体的使用方法:

class Rectangle
    attr_accessor :width
    attr_accessor :height
    attr_accessor :width2
    attr_accessor :height2

    def initialize(wdth, hgt)
        @width = wdth
        @height = hgt
    end

    def area()
        return @width * @height
    end

    def area2()
        return @width2 * @height2
    end

end

r = Rectangle.new(2,3)
r.width = 5    # give samename's variable value 给同名变量的变量赋值
r.height = 5
puts r.area()  # outputs is 25

r.width2 = 6   # not samename's variable create 无同名变量的变量创建
r.height2 = 6
puts r.area2() # outputs is 36

attr_reader: 实例变量只读 attr_writer: 实例变量可写 attr_accessor: 变量可读可写

  近来学习ruby的过程中,看到了拟态方法的概念,感觉很有意思。我们都知道拟态方法在ruby中无处不在,可以让代码更清爽更容易理解,比如

  obj.my_attribute=""就不必写成obj.my_attribute=(""),而更进一步的,像attr_accessor这样的类宏的实现方式也引起了我的兴趣。

看了网上的实现方式,自己动手试了一下。

class Module
    def var( method_name )
        inst_variable_name = "@#{method_name}".to_sym    # .to_sym
        p inst_variable_name        #:=>:@bar

        define_method method_name do
            instance_variable_get inst_variable_name
        end

        define_method "#{method_name}=" do |new_value|
            instance_variable_set inst_variable_name, new_value
        end

    end
end

class Foo
    var :bar
end

f = Foo.new            # p f.bar
p f.class              #:=>Foo
p f.class.instance_methods(false)      #:=>["bar", "bar="]
f.bar = "good"                         #:=>"good" method bar=
p f.bar                                #:=>"good" method bar

上面的var方法就类似于attr_accessor,对其中的instance_variable_get用代码进行一下说明:

class Fred
#attr_accessor :a #不要去掉注释,先直接运行
#attr_accessor :b

    def initialize(p1, p2)
        @a, @b = p1, p2
    end
end
fred = Fred.new('cat', 99)
puts fred.instance_variable_get(:@a)  #=> "cat"
puts fred.instance_variable_get("@b") #=> 99
#puts fred.a,fred.b,fred.a.class,fred.b.class 
=begin 上一句结果
cat
99
String
Fixnum
=end

我们都知道在ruby中:a等价于"a"但用前面的方法会更清爽,并且少写一个符号。