lazybios

《Ruby 元编程》读书笔记(一)

Ruby元编程

打开类

可以重新打开已经存在的类并对之进行动态修改,即使像String或者Array这样标准库的类也不例外。这种行为方式称之为打开类(open class)

猴子补丁

如果你粗心地为某个类添加了新功能,同时覆盖了类原来的功能,进而影响到其他部分的代码,这样的patch称之为猴子补丁(Monkeypatch)

类与模块

Ruby的class关键字更像是一个作用域操作符,而不是类型声明语句。class关键字的核心任务是把你带到类的上下文中,让你可以在里面定义方法。

每个类都是一个模块,类就是带有三个方法(new,allocate,superclass)的增强模块,通过这三个方法可以组织类的继承结构,并创建对象

Ruby中的类和模块的概念十分接近,完全可以将二者相互替代,之所以同时保留二者的原因是为了保持代码的清晰性,让代码意图更加明确。使用原则:

希望把自己代码包含(include)到别的代码中,应该使用模块

希望某段代码被实例化或被继承,应该使用类

模块机制可以用来实现类似其它语言中的命名空间(Namespace)概念

Ruby中的::符号

Ruby中常量的路径(作用域),类似与文件系统中的目录,通过::进行分割和访问,默认直接以::开头(例: :: Y)表示变量路径的根位置

什么是对象

对象就是一组实例变量外加一个指向其类的引用。对象的方法并不存在于对象本身,而是存在于对象的类中。

什么是类

类就是一个对象(Class类的一个实例)外加一组实例方法和一个对其超类的引用。Class类是Module类的子类,因此一个类也是一个模块。

load与require方法的异同

通过load和require都可以进行导入别人的代码,不同的是load方法用来加载代码,如果不希望污染当前的命名空间,需要通过load(‘file.rb’,true)显式的要求创建一个匿名模块来,接管file.rb的常量,require用于导入类库,此外,就加载次数上load方法每次调用都会再次运行所加载文件,require则对每个库文件只加载一次。

prepend、include与祖先链

祖先链用于描述Ruby对象的继承关系,因为类与模块是父子关系,所以祖先链中也可以包含模块,prepend与include分别可以向链中添加模块,不同的是调用include方法,模块会被插入祖先链,当前类的正上方,而prepend同样是插入到祖先链,但位置其他却在当前类的正下方,另外通过Class.ancestors可以查看当前的祖先链

private规则

不能通过明确指定接受者来调用私有方法。私有方法只能通过隐性的接受者self调用(Object#send是个例外)

self相关

调用一个方法时,接受者会扮演self角色 任何没有明确指定接受者的方法调用,都当做是调用self的方法 定义一个模块(或类)时,该模块(或类)会扮演self角色

对象、类与模块之间关系

对象、类、模块关系图

上面Module.class指向的也是Class类,可以理解为上面方框内容均为Class,但他们的父子组织关系通过superclass建立并存在异同,可以通过Class.ancestors查看。

-待续-

微信关注「日拱一卒」公众号