Ruby Digest(2)
ruby的基本rule都是普遍试用的,不像有些语言总是有些exception。所以只要知道了ruby基本规则,就可以自行推倒各种复杂的规则。
方法method
ruby为动态类型检查,只有run的时候会报错。
动态方法 Dynamic Method
在执行过程中生成一下方法(原本方法名都是常量,但动态生成时,方法名就可以是变量了)
class MyClass
def my_method(my_arg)
my_arg * 2
end
obj = MyClass.new
obj.my_method(3)
obj.send(:my_method, 3) #动态调用,:my_method可以为变量
obj.send(method_name)
称为动态分发,因为method在运行时才确定- YAML K/V方式存储配置文件的格式(or 序列化格式)
- 只调用以test开头的方法,有时被称为 模式分发(Pattern Dispath)
动态定义方法 Defining Methods Dynamically
Module#define_method()
class MyClass
define_method :my_method do |my_arg|
my_arg * 3
end
obj = MyClass.new
obj.send(:my_method, 3) # => 9
- 显然上面的 :my_method 可更换为变量,也就达到了动态定义方法名的目的
class MyClass
['a', 'b', 'c'].each do |name|
define_method (name) {
name * 3
}
end
end
这样就定义了MyClass#a MyClass#b Myclass#c
method_missing()方法
又称 幽灵方法(Ghost Method) 因为 MyClass#method_name其实不存在
class Lawyer; end
nick = Lawyer.new
nick.talk_simple
=> NoMethodError: undefined method 'talk simple'
- 实际上调用不存在的方法 会进入 method_missing方法
method_missing
为一个私有方法nick.send :method_missing, :my_method
可调用私有方法
class Lawyer
def method_missing(method, *args)
puts "You called: #{method}(#{args.join(', ')})"
puts "(You also passed it a block)" if block_given?
end
end
bob = Lawyer.new
bob.talk_simple('a', 'b') do
# a block
end
=> You called: talk_simple(a, b)
(You also passed it a block)
这样就可以动态定义一个方法了
- method_missing可以很容易做Proxy, class A 里有个class B的实例,当用户调 a.b_method 可以自动转发到 b.b_method
- delegate 库帮我们做了动态代理的method_missing的撰写
- 幽灵方法找不到对应的方法, 为了避免这个;可以复写respond_to? 申明method_missing中实现了某个方法
- method_missing中尽量不调用别的方法,否则容易进入死循环
- best-practice: 在method_missing中制定要处理的未知Method名称集合
- 父类占用了某个函数名,就不能进入method_missing了,此时最好使用白板类,即没有任何方法的基类
- ruby1.9起 BasicObject的子类即为白板类
动态方法 VS 幽灵方法
- 动态方法实际定义了方法,因此占用了空间
- 幽灵方法实际并没定义方法,因此不占用空间,但是比较慢;
- 一个合理的方案是,当一个幽灵方法第一次被调用时,动态生成该方法;
- 这样既节约了内存,又加快了函数调用速度;
- 该方案称为 lazy loading, 仅在使用时加载;