最近读了下 《Ruby元编程》, 收获颇多, 以下是关于一些概念的理解.
下面是示例代码,和对象模型. 下文都是基于这个例子展开的.
def top_level_private_method
'Object#top_level_private_method'
end
def top_level_public_method
'Object#top_level_public_method'
end
def self.top_level_singleton_method
'Object#top_level_singleton_method'
end
class C
def initialize(value = 0)
@a_value = value
end
def self.c_class_method
'C.c_class_method'
end
def c_public_method
"C#c_public_method with a_value = #{@a_value}"
end
private
def c_private_method
"C#c_private_method with a_value = #{@a_value}"
end
protected
def c_protected_method
"C#c_protected_method with a_value = #{@a_value}"
end
end
class D < C
attr_accessor :x, :y
protected :x=, :y=
def initialize(x = 0, y = 0)
@x, @y = x, y
end
def swap(other)
tmp_x, tmp_y = @x, @y
@x, @y = other.x, other.y
other.x, other.y = tmp_x, tmp_y
return self
end
end
obj = D.new
class << obj
def a_singleton_method
'obj#a_singleton_method'
end
end
end
对象模型图, 使用draw.io画的: 源文件
关于对象模型
在Ruby中,处处是对象. 变量仅仅是一个对象的引用(类似C语言的指针). 对象通过C.new类方法实例化. 一个对象是一个内存区域,区域里包含:
- 各个实例变量(像上面说的,变量其实就是一个指针地址)
- 一个所属类的引用
关于类,模块
类也是一个对象, 不同于普通的对象, 一个类包含了类实例方法定义, 类的superclass是模块, 类与模块的区别仅仅是:
- 类可以实例化
- 类可以继承
一般来说, 模块中定义的方法仅可以通过mixin到一个类中使用.但是也可以定义像类方法类似的模块方法.
module M
def mixin_method
'can only use with a class, M.mixin_method not work'
end
def self.moudle_method
'can be called by M.moudle_method, not work in a mixin class'
end
end
关于方法调用
方法调用时序
方法调用要搞清楚几点:
- 从对象模型中找到对应的方法,若找不到,则会调用 默认的method_missing(), 如若需要,可以重写method_missing()魔法实现Ghost method.
- 每一行代码执行都需要一个当前对象(self), 需要搞清楚self到底是谁
- 当方法调用时, 接收者就是self
- 所有实例变量都是self对象的实例变量
- 每一个方法必须指定一个接收者, 如果没有指定,将使用隐含接收者self
private / protected / public 方法
private方法:
- 如若指定接收者(即便写的是self.), 不能调用该方法
- 子类可以调用父类的private方法, 如果对应的方法中有实例变量, 这些变量也将是子类实例化对象的实例变量
protected方法:
- 首先可以像private那样用
- 仅在同一个类(派生类)中时可将该方法作为实例方法调用, 主要用于同一个类(派生类)不同对象之间的数据交换(当数据没有公开接口时)
示例: 参考代码的class D
initialize()方法
initialize()是一个private方法, 仅在Class.new()的时候调用.
如何使用不同的构造函数
- 方法一: 缺省参数
- 方法二: 定义不同的类方法,在类方法中调用new()
关于作用域
- 仅当遇到module, class, def关键字, 作用域才会切换.
- ruby中的作用域无嵌套一说,即不同的作用域就是不同的作用域,无内部作用域可以看到外部作用域的说法
- 进入class C定义,当前作用域self = C
- 进入module M定义, 当前作用域self = M
- 方法,仅当方法调用时,才进入方法的作用域, self=接收者对象
- 进入块, 不会切换作用域
关于顶层类 和顶层对象
- 顶层对象是main, 是一个Object对象.
- 顶层类是Object, 在顶层定义的方法会添加到Object的private_instance_methods