“Ruby元编程技术”的版本间的差异
来自Dennis的知识库
Dennis zhuang(讨论 | 贡献) |
Dennis zhuang(讨论 | 贡献) (→块,Proc,Lambda和方法) |
||
(未显示1个用户的4个中间版本) | |||
第109行: | 第109行: | ||
== instance_eval() == | == instance_eval() == | ||
+ | |||
+ | 在对象的上下文中执行一个代码块,ruby 1.9引入了instance_exec,可以为代码块传入参数。 | ||
+ | |||
+ | 主要用途: | ||
+ | |||
+ | * 上下文探针: 可以方便地“窥探”对象细节,虽然不建议这么做(破坏封装性) | ||
+ | * Clean Room(洁净室): 创建一个对象,仅仅是为了在其中执行代码块,通常这个对象会提供一些辅助方法。一般用在创建DSL的场景。 | ||
+ | |||
+ | == 块,Proc,Lambda和方法 == | ||
+ | |||
+ | * lambda和proc的区别: | ||
+ | ** 对return处理不同:proc从定义的原始上下文中返回,可用于实现non-local exit,而lambda从自身返回 | ||
+ | ** 对参数个数的检查不同,lambda更为严格 | ||
+ | |||
+ | * proc方法在ruby 1.8中等价于lambda,在ruby 1.9中才是Proc.new | ||
+ | |||
+ | * 通过Object#method可以获取方法对象,并且可以使用unbind和bind来重新绑定对象。 | ||
+ | |||
+ | * 块和proc的转换利用&操作符。 |
2013年2月1日 (五) 14:55的最后版本
目录 |
[编辑] 声明
- 本Wiki上的任何文字信息均在GNU自由文档许可证1.3或更高版本下发布,如果用于任何商业用途都需经本人同意。任何转载都请注明出处。
- 本Wiki上的内容来自本人的学习笔记,来源可能包括原创、书籍、网页、链接等,如果侵犯了您的知识产权,请与本人联系,我将及时删除。
- 我的联系方式 killme2008@gmail.com
[编辑] 简介
读《Ruby元编程》的笔记
[编辑] Open Class
class更像是作用域操作符,而不仅是类型声明语句。随时可以打开一个class定义或者覆写方法:
#为String添加新方法 class String def to_alphanumeric self.gsub /^[\w\s]/, "" end end
[编辑] 对象模型
- 对象由一组实例变量和一个类的引用组成。
- 对象的方法存在与对象所属的类中(从类的的角度来看,它们叫做实例方法)
- 类本身是Class类的对象。类的名字不过是一个常量而已
- Class类是Module的子类。一个模块基本上是由一组方法组成的包。类除了具有模版的特性之外,还可以被实例化(通过new方法)以及本组织为层次结构(通过superClass方法)
- 常量像文件系统一样,是按照树形结构组织的。其中模块和类的名字扮演目录的角色,其他普通的常量则扮演文件的角色
- 每个类都有一个祖先链,这个链从自己所属的类开始,向上直到BasicObject类结束
- 当调用一个方法时,Ruby首先向右一步来到接受者所属的类,然后一直向上查找祖先链,直到找到该方法,或者到达链的顶端为止
- 每当一个类包含一个模块时,该模块会被插入在祖先链中,位置在该类的正上方
- 当调用一个方法时,接收者会扮演self的角色
- 当定义一个模块时(或者类)时,该模块扮演self的角色
- 实例变量永远被认定为self的实例变量
- 任何没有明确指定接收者的方法调用,都当成调用self方法
module M1 end module M2 end module M3 end
class A include M1 end
class B < A include M2 include M3 end B.ancestors => [B,M3,M2,A,M1,Object,Kernel,BasicObject]
[编辑] 内核方法
通过给Kernel增加方法来为所有对象增加方法。
[编辑] 动态方法
- 动态派发,利用send或者public_send(1.9加入)来动态调用函数
- 动态定义方法,使用define_method来动态定义方法
[编辑] Method Missing
- method_missing包含在kernel模块中,默认抛出无法找到方法的error
- 对象可以复写method_missing来动态响应方法调用,思考下,这其实就是消息传递。
- 用途:
- 幽灵方法:用来响应不曾明确的方法
- 动态代理: 例如为web service创建本地动态代理
- delegate标准库,委托模式
- const_missing方法,用于常量
- 注意事项:
- 避免无限循环,适当调用super来终止循环。
- 最好在一个白板对象上使用幽灵方法,避免重名,如何得到一个白板对象?使用undef_method方法来移除所有方法,或者继承BasicObject(Ruby 1.9)。
- 适当定义respond_to?来响应幽灵方法。
class Computer instance_methods.each do | m | undef_method m unless m.to_s =~ / ^__ | method_missing | respond_to?/ end def method_missing(name,*args) ...... end end
[编辑] 扁平作用域(Flat scope)
写一些简单脚本的时候,经常遇到这个需求,希望在类或者方法里访问main里的变量,如:
x=1 def test x = x +1 end test => NoMethodError: undefined method `+' for nil:NilClass
from (irb):6:in `test' from (irb):8
但是Ruby是没有inner scope这样的概念,方法、类和模块里的变量不会访问到外层的变量,要想访问就需要一点小技巧:
x=1 define_method :test do x=x+1 end test => 2
利用闭包来扁平化scope,跨越def,class和module封闭的作用域。可以使用define_method,Class.new和Module.new的方式来扁平化作用域。
[编辑] instance_eval()
在对象的上下文中执行一个代码块,ruby 1.9引入了instance_exec,可以为代码块传入参数。
主要用途:
- 上下文探针: 可以方便地“窥探”对象细节,虽然不建议这么做(破坏封装性)
- Clean Room(洁净室): 创建一个对象,仅仅是为了在其中执行代码块,通常这个对象会提供一些辅助方法。一般用在创建DSL的场景。
[编辑] 块,Proc,Lambda和方法
- lambda和proc的区别:
- 对return处理不同:proc从定义的原始上下文中返回,可用于实现non-local exit,而lambda从自身返回
- 对参数个数的检查不同,lambda更为严格
- proc方法在ruby 1.8中等价于lambda,在ruby 1.9中才是Proc.new
- 通过Object#method可以获取方法对象,并且可以使用unbind和bind来重新绑定对象。
- 块和proc的转换利用&操作符。