3-13《元编程》第5章Class Definitions 3-14(5-4Singleton Classes,2小时)3-15(3小时✅)
类宏- 环绕别名
- singleton class
5.1 Class Definitions Demystified
5.11 Inside Class Definitions
美 [,dɛfɪ'nɪʃən]
Self关键字:Ruby的每一行代码都会在一个对象中被执行--这个对象就是所谓的当前对象,用self表示。
class and module 也是 object, so class also can be "self"
5.12 The Current Class 当前类
Ruby程序的任何位置,总会存在一个当前对象。因此就有一个当前类/模块存在。定义一个方法时,这个方法就会成为当前类的一个instance method.
1.在程序的顶层,当前类是Object,这是main对象的类。(所以在顶层定义方法会成为Object的private method。)
2.在一个方法中,当前类就是当前对象的类。在一个方法中嵌套另一个方法,新方法会定义在self所属的类中。
3.当用class/module关键字时,当前对象self转换为class/module.这个类也称为当前类。
class_eval
如何在不知道类名字的情况下,打开一个类? 使用Module#class_eval方法(module_eval)
例子,下面例子给String增加了一个新的方法m:
p self.class
p self.class
class_eval方法同时修改了self和当前类 。
class_eval方法和class比较:
- 灵活:可以对任何代表类的变量使用class_eval, 而class关键字只接收常量命名。
- scope: class_eval flatten the scope可以接收block外部scope的变量. 而class关键字是Scope Gate.
module_eval/class_eval 一样,module_exec/class_evec可以接收额外的代码块做参数。class_exec(arg...) {|var...| block } → obj
instance_eval 和 module_eval/class_eval 的 选择:
- instance_eval打开非类的对象,可以修改对象的方法和实例变量
- class_eval打开类,然后用def定义方法。
- 如果要打开的一个对象也是类/模块,选择可以准确表达你的目的的方法。
小结:
- Ruby总是追踪当前类/模块的引用,所有使用def的方法都成为当前类的实例方法。
- 类定义,当前类就是self--正在定义的类
- 如果有一个类的引用,可以用class_eval/module_eval打开这个类。(打开类:对已经存在的类进行动态修改)
5.13Class Instance Variables 类实例变量
Ruby解释权规定所有的实例变量都属于当前对象self。
类的实例变量,类的对象的实例变量。是两回事。
class Myclass
类变量:@@var,可以被子类和类的实例调用,为了避免以外,一般不使用类变量
5.3 Singleton Methods 单件方法
单件方法可以增强某个对象(类也是对象),是ruby最常见的特性。
Object#define_singleton_method:
define_singleton_method(symbol) { block } → symbol
#或者这么写,用Object#define_singleton_method定义单件方法
5.32 The truth about Class Methods
详细(5.4Singleton Classes)
AClass.a_class_method 这是在一个由常量引用的对象(类)上调用方法。
an_object.a_method 这是在一个由变量引用的对象上调用方法。
语法完全一样。
类方法的实质是: 它是一个类的单件方法。
object可以是对象引用,类,self。底层机制一样的。
def object.method
...
end
Duck Typing:鸭子类型。
Ruby这样的动态语言,对象的类型并不严格与它的类相关,“类型”只是对象能相应的一组方法。这也叫鸭子类型。 116页
5.33Class Macro类宏
什么是拟态方法?看起来像关键字或者别的,就是不像方法,但其实是方法。
puts, private, protect, attr_accessor, attr_read, attr_write(类宏)
什么是类宏?
普通的方法,看起来像关键字,其实是在类里定义好了。如attr_accessor, attr_read, attr_write。 类宏依靠类方法实现。
本例子:类宏用了类方法实现。
也使用了:
Dynamic method(Module#define_method):用于普获对旧方法的调用,并把调用转发给重命名的新方法。
Dynamic#dispatch(Module#send)
Kernel#warn: warn(msg, ...) → nil, 一般用于测试代码。
class Book
Warning: lend_to_user() is deprecated. Use lend_to()
Lending to bill
5.4Singleton Class
5.41 the Mystery of Singleton Methods
对象的单件方法不存在对象里,也不存在它的类和超类中。
单件方法存在哪里?类方法是单件方法的特例,它又存在哪里?
答案:见5.42(绿色框)。
5.42 Singleton Classes Revealed
被隐藏起来,需要使用Object#singleton_class或class<<关键字 得到它
#两种显示对象的单件类的代码
由⬆️代码可知:
一个对象的单件方法(可以有多个单件方法) --存储在--> 一个单件类中;
因此,一个单件类也只有这么一个实例对象。
5.43 单件类在ancesstors中的位置。
p obj.singleton_class.ancestors
#=>[#<Class:#<D:0x00007fa9af03cc98>>, D, C, Object, Kernel, BasicObject]
obj->#obj->D->C->Object
Ruby模型对象的7条规则:
- 只有一种对象,要么是普通对象,要么是模块
- 只有一种模块,可以是一个普通模块,一个类或者一个单件类
- 只有一种方法,它存在于一个模块--通常是一个类中
- 每个对象(包括类)都有自己的“真正的类”--要么是一个普通类,要么是一个单件类
- 除了BasicObject类没有超类外,每个类有且只有一个祖先--要么是一个类,要么是一个模块。这意味着任何类只有一条向上的,直到BasicObject的祖先链
- 一个对象的单件类的超类是这个对象的类:一个类的单件类的超类是这个类的超类的单件类
- 调用一个方法,Ruby先向右迈一步进入接受者真正的类,然后向上进入祖先链。这是Ruby查找方法的方式。
类方法的语法:
class Myclass
def self.another_class_method; end
end
或者 (这是最好的选择✅,可以在class<<关键字中定义多个类方法,方便阅读代码。)
class Myclass
class << self
def yet_another_class_method; end
end
end
不建议:
def Myclass.a_class_method; end
单件类和instance_eval方法
class_eval方法会修改self,同时也就变更了当前类。instance_eval内修改self为调用它的receiver.
如果在instance_eval的{}中,定义一个def方法,当前类变为receiver的单件类, 这个方法成为receiver的singleton m
ethod.
所以,instance_eval也会变更当前类.不过Ruby程序员一般不用这个特点定义方法。
instance_eval的标准含义: 我想修改当前self.
“类属性”
Ruby对象没有属性的概念。所谓属性只不过是用拟态方法加上的一对儿读写的方法罢了。
这种简写的拟态方法,如attr_*也称为类宏Class Macro,其实就是普通的方法而已。
因此,类属性就是是这个类自己用的方法,类方法,放到这个类的单件类里.
5.5 Module Trouble
如何用包含模块的方式来定义一个类方法?
在模块中定义普通的实例方法,然后把模块放到类的单件类中,成为类方法。这称为Class Extension 类扩展
这种方法同样适用于对象,因为类方法本身就是单件方法的特例。所以可以把Module包含进对象的单件类中。这称为Object Extension.
Object#extend
类扩展和对象扩展使用普遍,所以打包代码做了一个extend方法。相当于快捷方式。
module Mymodule
5.6Method Wrappers
方法包装器
- Around Aliases
- Refinement Wrapper
- Prepended Wrapper
用途:有一个不能直接修改(在一个库中)或者修改的地方太多(怕漏掉)的Method, 我们希望为这个方法包装额外的功能。可以使用Method Wrappers.
Ruby提供alias关键字,为顶级作用域Object下提供帮助。
alias :new :old #⚠️ 没有逗号。
环绕别名
名字类似指针
- 给方法a定义一个别名b
- 重新定义a,此时我的理解b方法是过去的那个方法,a重新定义了所以是新的方法
- 在新的方法a中调用b方法,就叫环绕别名。
绝大部分Ruby操作符合实际上是方法,例如整数的+操作符是Fixnum#+方法的语法糖。
问题:重新定义+方法。让(x+y)的结果返回(x+y+1).?
解答:只能用环绕别名的方法,因为新的+方法依赖于旧的+方法。super方法不能重复用了
细化封装器 Refinement Wrapper
使用refine(mod){},配合using方法。作用域是:
- refine内部
- 从using开始到文件结束(如果是在顶层上下文中调用using)
- 或者从using开始到模块结束(如果是在模块中调用using)
module StringRefinement
Prepend Wrapper 下包含包装器(祖先链:当前类的下面)
#把包含的模块插入祖先链下方,而非上方。这意味着prepend方法包含的模块可以覆写该类的同名方法,同时可以通过super调用该类中的原始方法。
5.8小结
- 类定义对self(调用方法时默认的receiver)和当前类(定义方法时默认的所在地)的影响
- singleton_method, 单件类,类方法。 从新认识了对象模型(7条规则),和方法查找。
- 新的法术,类实例变量(类自己用不能继承),类宏(拟态简写),下包含包装器
- 模块就是类
3-13《元编程》第5章Class Definitions 3-14(5-4Singleton Classes,2小时)3-15(3小时✅)的更多相关文章
- 3-8《Ruby元编程》第二章对象模型
<Ruby元编程> 第二章 对象模型 类定义揭秘inside class definitions: class关键字更像一个作用域操作符,核心作用是可以在里面随时定义方法. [].meth ...
- 一道模板元编程题源码解答(replace_type)
今天有一同学在群上聊到一个比较好玩的题目(本人看书不多,后面才知是<C++模板元编程>第二章里面的一道习题), 我也抱着试一试的态度去完成它, 这道题也体现了c++模板元编程的基础和精髓: ...
- 初识C++模板元编程(Template Mega Programming)
前言:毕设时在开源库上做的程序,但是源码看得很晕(当时导师告诉我这是模板元编程,可以不用太在乎),最近自己造轮子时想学习STL的源码,但也是一样的感觉,大致了解他这么做要干什么,但是不知道里面的机制. ...
- 3-11 《Ruby元编程》第4章block块 3-12
第4章代码块blocks 基础知识 作用域:用代码块携带variables through scopes 通过传递block给instance_eval方法来控制作用域. 把block转换为Proc, ...
- C++模板元编程(C++ template metaprogramming)
实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...
- 异步编程系列06章 以Task为基础的异步模式(TAP)
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- atitit.元编程总结 o99
atitit.元编程总结 o99.doc 1. 元编程(Metaprogramming) 1 2. 元编程的历史and发展 1 3. 元类型and元数据 1 4. 元编程实现方式 2 4.1. 代码生 ...
- C++ 元编程 —— 让编译器帮你写程序
目录 1 C++ 中的元编程 1.1 什么是元编程 1.2 元编程在 C++ 中的位置 1.3 C++ 元编程的历史 2 元编程的语言支持 2.1 C++ 中的模板类型 2.2 C++ 中的模板参数 ...
- ES6中的元编程-Proxy & Reflect
前言 ES6已经出来好久了,但是工作中比较常用的只有let const声明,通过箭头函数改this指向,使用promise + async 解决异步编程,还有些数据类型方法...所以单独写一篇文章学习 ...
- Python类元编程
类元编程是指在运行时创建或定制类.在Python中,类是一等对象,因此任何时候都可以使用函数创建新类,而无需用class关键字.类装饰器也是函数,不过能够审查.修改,甚至把被装饰的类替换成其他类.元类 ...
随机推荐
- git提交时候出错
Please make sure you have the correct access rights and the repository exists. 解决方案: 主要原因是没有加载keygen ...
- python实现常量const
新建const.py: #-*-coding:UTF-8-*- #Filename: const.py # 定义一个常量类实现常量的功能 # # 该类定义了一个方法__setattr()__,和一个异 ...
- 应用程序无法正常启动0xc000007b怎么解决
解决方法两种: 1. 网上搜索中最常见的,缺少DirectX 9 ,去下载一个安上就OK了. 2.第二种情况比较操蛋,其实报的错误应该是:mfc100u.dll丢失 .我在两台电脑上装了相同系统后,台 ...
- Linux基础命令---find
file 判断指定文件的文件类型,它依据文件内容判断,并不依据扩展名.此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.openSUSE.Fedora. 1.语法 ...
- phonegap 开发案例
PhoneGap-Android-HTML5-WebSocket 不使用任何框架,教你制作网页滑动切换效果 http://www.csdn.net/article/2012-04-17/2804644 ...
- CocoaPods的安装及使用
CocoaPods安装使用及配置私有库 http://www.exiatian.com/cocoapods%E5%AE%89%E8%A3%85%E4%BD%BF%E7%94%A8%E5%8F%8A%E ...
- Python3基础 input 输入浮点数,整数,字符串
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- HDU 4135 Co-prime(容斥:二进制解法)题解
题意:给出[a,b]区间内与n互质的个数 思路:如果n比较小,我们可以用欧拉函数解决,但是n有1e9.要求区间内互质,我们可以先求前缀内互质个数,即[1,b]内与n互质,求互质,可以转化为求不互质,也 ...
- 手机常用meta标签-有注释
<!-- 设置字体编码 --> <meta charset="UTF-8"> <!-- 视图窗口,移动端特属的标签. --> <meta ...
- maven 插件在线安装
NO.1 在Eclipse中安装Maven插件安装详解 前言 本来是没打算写博客的,作为一个13年毕业的菜鸟,自认为水平太渣写不出什么好文章,但是前些日子看到一篇鼓励性质的文章说,技术人员的成长靠的就 ...