《Ruby元编程》 读书笔记1

对象,类和模块

Posted by Sheldon on September 12, 2015

元编程的定义

  • 元编程是能变现代码的代码
  • 元编程是编写能在运行时操作语言构件的代码

基本概念

  • 类的本质也是对象
  • 对象就是一组实例变量外加一个指向其类的引用。对象的方法并不存在于对象本身,而是存在于对象的类中,即类的实例方法
  • 类就是一个对象(Class类的一个实例)外加一组实例方法和一个对其超类的引用。Class类是Module类的子类,因此一个类也是一个模块
  • 每个类都是一个模块,类就是带有三个方法(new,allocate,superclass)的增强模块,通过这三个方法可以组织类的继承结构,并创建对象
  • Ruby的class关键字更像是一个作用域操作符,而不是类型声明语句。class关键字的核心任务是把你带到类的上下文中,让你可以在里面定义方法
  • Ruby中的类和模块的概念十分接近,完全可以将二者相互替代,之所以同时保留二者的原因是为了保持代码的清晰性,让代码意图更加明确。使用原则: 希望把自己代码包含(include)到别的代码中,应该使用模块;希望某段代码被实例化或被继承,应该使用类
  • 模块机制可以用来实现类似其它语言中的命名空间(Namespace)概念,如: Rake::Task ,Rake就是用来充当常量容器的模块
  • 任何以大写字母开头的引用(包括类名和模块名)都是常量, 而且可以修改常量的值, Ruby中常量和变量最大的区别在于作用域不同
  • Ruby中常量的路径(作用域),类似与文件系统中的目录,通过::进行分割和访问,默认直接以::开头(例: :: Y)表示变量路径的根位置
  • 不能通过明确指定接受者来调用私有方法。私有方法只能通过隐性的接受者self调用(Object#send是个例外)
  • 调用一个方法时,接受者会扮演self角色 任何没有明确指定接受者的方法调用,都当做是调用self的方法 定义一个模块(或类)时,该模块(或类)会扮演self角色

类与对象与模块的关系

打开类,猴子补丁和细化

  • 可以重新打开已经存在的类并对之进行动态修改,即使像String或者Array这样标准库的类也不例外。这种行为方式称之为打开类
  • 如果你粗心地为某个类添加了新功能,同时覆盖了类原来的功能,进而影响到其他部分的代码,这样的patch称之为猴子补丁
  • 细化是对打开类的全局修改的一种解决方法,在模块中使用refine指明需要修改,然后使用using这个模块是其生效,细化就有了一个作用域,using后到模块结束或者文件结束

祖先链

  • 祖先链用于描述Ruby对象的继承关系,因为类与模块是父子关系,所以祖先链中也可以包含模块
  • 使用include方法,模块会被插入祖先链,当前类的正上方
  • 使用prepend方法,模块也会被插入到祖先链,但位置其他却在当前类的正下方
  • 查找方法的方式,向右一步,再向上
  • 一个模块只会在一条祖先链中出现一次,故多次插入相同的模块,只有第一次生效

load与require方法的异同

  • loadrequire都用来导入外部的代码
  • load方法用来加载代码,如果不希望污染当前的命名空间,需要通过load('motd.rb',true)显式的要求创建一个匿名模块来,接管motd.rb的常量;
  • require用于导入类库;
  • load方法每次调用都会再次运行所加载文件,require则对每个库文件只加载一次

一些方法和作用

  • obj.class 询问对象的类
  • obj.class.instance_methods, obj.methods 询问对象的类的实例方法
  • obj.class.instance_methods(false) 不包括继承而来的方法
  • obj.instance_variables 询问对象的实例变量
  • Module#constants (实例方法) 返回当前范围内的所有常量
  • Module.constants (类方法) 返回当前程序中所有顶层常量(包括类名)
  • Module.nesting 获取当前代码所在路径
  • obj.class.ancestors 查看当前类的祖先链