ruby正则表达式:Ruby 101:对象和思路方法

  从静态思路方法说起

  在上篇文章末尾我们提到了受保护静态思路方法……受保护静态思路方法??Rubyprotected不是用来向相同类型区别例子开放受限思路方法访问吗(忘记protected使用方法了?不要紧回去上篇文章复习下吧)如果把它用于静态思路方法那么我该向参数传入什么?

  在回答这些问题的前我们先来看看最简单不带任何参数静态思路方法假设我有个空Class1类如果我试图method1静态思路方法那么我将会被告知没有这个思路方法:



  图 1

  在Ruby里所有类最终都会继承自Object类(这个说法其实不够准确但就目前而言你大可放心这样理解)如果我试图method1静态思路方法那么显然我也将会被告知没有这个思路方法:



  图 2

  还记得Ruby允许我们重新打开并修改个类吗如果忘记了不要紧回去第篇文章复习下吧下面我们将会通过这种方式向Class类添加method1思路方法:



  图 3

  接着我们再试次Class1类及其基类method1思路方法:



  图 4

  噢买瓜!这到底是如何回事?

  先别急解释留到后面现在让我们把注意力集中到我们目标上——受保护静态思路方法把上面发现和上篇文章访问控制知识结合起来就得到创建受保护静态思路方法办法了:



  图 5

  下面我们来试下这个思路方法:



  图片看不清楚?请点击这里查看原图(大图)

  图 6

  显然我们成功了接下来我们使用上面发现创建个odd_equals思路方法根据length_of_name思路方法返回值判断两个类型是否相等:



  图 7

  最后我们来试下这个奇怪判等思路方法:



  图 8

  哇实在是太不可思议了!我在Class类里创建例子思路方法到了Class1类和Object类就变成静态思路方法了难不成……?

  我想你已经猜到了Class1类和Object类是Class类例子:



  图 9

  而Class1类和Object类静态思路方法则是Class类例子思路方法事实上Ruby没有静态思路方法这种说法这种类似静态思路方法东西其实叫做类思路方法换句话说类也是对象……

  类也是对象

  类也是对象?如果类也是对象那么Class类是谁例子?答案是Class类自己:



  图 10

  换句话说它是个Class对象还记得Object类吗?嗯Object是个类而类又是对象于是 Class是个类Object是个类Object是个对象Class是个对象……从类角度来看Class类应该先于Object类而存在;而从对象角度来看Object对象应该先于Class对象而存在哈哈我们陷入先有鸡还是先有蛋悖论了……嘿嘿你可别真陷进去了哟如果你感到混乱那就忽略它吧就目前而言你只需要记住类也是对象就行了

  如果类也是对象那么它也应该可以拥有例子变量但这种例子变量有什么用呢它和我们的前看到例子变量有什么区别呢它和类变量又有什么联系呢?我们知道例子变量是和例子绑定创建例子变量最直接做法是在例子思路方法里执行赋值操作假设我们有个Class1类如果我们想为它创建例子变量那么我们就要回到Class1类类里读起来有点新鲜和拗口但操作起来却非常简单:



  图 11

  @value1变量是Class类例子变量目前只能通过_value1思路方法设值_value1思路方法又是Class类例子思路方法只能通过Class类例子访问于是若要_value1思路方法就得先有Class类例子那么谁是Class类例子?就上图来而言Class1类和Class类自己都是Class类例子为了避免思维过于纠结我们还是选择Class1类吧:



  图 12

  如果我想获取或者输出@value1变量值呢?最直接做法当然是在Class类里创建个思路方法然而仔细观察_value1思路方法你会发现它和我们在前两篇文章里看到类思路方法没啥两样这是否意味着我们在Class1类里创建类思路方法也能访问@value1变量呢?试下就知道了:



  图 13

  噢耶成了!现在请研究下:我们在Class1类里创建例子思路方法能否访问@value1变量?为什么?对于第个问题我们试下就知道了:



  图 14

  从上图可以看到@value1变量对于Class1类pr_value1例子思路方法是不可见这是否意味着我们在Class类里创建@value1变量和我在Class1类里创建@value1变量是互不相干呢?嗯下就知道了:



  图 15

  答案已经很明显了但是为什么呢?它们名字是使用时候又没有附加任何标识Ruby究竟是如何区分它们呢?秘密就在self上!还记得Ruby如何限制私有思路方法吗(如果忘记了不要紧回去上篇文章复习下吧)在Ruby里任意个时刻都有个默认对象用self来表示上面两个@value1变量的所以相互独立在Ruby碰到它们时候self分别指向两个区别对象在类思路方法里self指向类而在例子思路方法里self指向类例子:



  图 16

  换句话说上面两个@value1变量隶属于两个区别对象自然不会混到事实上我们通常会把这种和类绑定例子变量叫做类例子变量( instance variable)以便和例子变量区分开来

  现在请研究下:在类定义以内、任何思路方法定义以外地方比如说上图行和第 2行的间self指向什么?嗯?这种夹缝的地也有默认对象?当然有:



  图 17

  从上图可以看到此处self和类思路方法里self都是指向类这是否意味着我们也可以在里创建类例子变量?我们不妨试试看:



  图 18

  从上图可以看到这里也可以创建类例子变量那么这种做法和前面有什么区别呢?你可能会说前面创建@value1变量在Class1类和Class2类里都可用而这里创建@value2变量只能在Class2类里可用到底是不是这样呢我们试下就知道了为了避免干扰我们使用个干净Class3类来做试验:



  图 19

  从上图可以看到在我们在Class类里创建_value1例子思路方法的前@value1变量根本就不存在!为什么?Ruby例子变量是按需创建在你对它们进行赋值操作的前它们是不存在(如果你忘记这部分内容了不要紧回去上篇文章复习下吧)换句话说Class3类并没有从第种做法那里占到什么便宜事实上类型区别例子在某个时刻也可能有着完全区别例子变量

  说到这里你可能会问类变量和类例子变量都属于类那么它们的间有什么区别?第类例子变量只能被类思路方法直接访问而类变量则可以被类思路方法和例子思路方法直接访问;第 2类例子变量值和单个类挂钩而类变量值则和某个继承体系挂钩猜猜下面代码输出是什么:



  代码 1

  答案是3、4、4什么?最后个竟然是4?没错类变量值是和整个继承体系而不是单个类挂钩当我们创建Rectangle类例子时我们改变了@@sides变量这将影响整个继承体系我们期望变量值在类各个例子中保持但在区别类中保持独立此时就需要类例子变量了:



  代码 2

  这样输出就没问题了值得注意类例子变量不能被例子思路方法直接访问为了能在例子思路方法里访问它我们得先为它创建个类思路方法用于返回它然后通过self.获得当前例子最后通过这个类访问刚才创建类思路方法从而获取类例子变量道路似乎非常曲折不过如果你把类和它例子看作两个独立对象那么理解起来应该畅顺很多

  朋友们请系好安全带接下来旅程将会更加惊险!

  对象思路方法

  既然类是Class类例子这是否意味着我们可以通过Class类思路方法创建个类并通过这个类思路方法创建它例子?我们试试看吧:



  图 20

  正如你看到这条路行得通如果我想为Triangle类提供个sides类思路方法用于返回 3角形边数我该如何做呢?既然Triangle类是Class类例子你可能会说在Class类里创建不就行啦?好我们试试看:



  图 21

  看起来似乎没问题但是如果我再创建个Rectangle类然后sides思路方法那么问题就来了:



  图 22

  很显然这不是我们想要如何办?有人可能会建议既然Triangle类和Rectangle类都是Class类例子不妨考虑使用@sides变量来保存边数然后在sides思路方法里返回它@sides变量可以通过Class类initialize思路方法我们试试看但为了避免干扰我们打开个新irb:



  图 23

  看起来似乎没问题如果我再创建个Person类呢?



  图 24

  噢出错了!如何回事?看看信息原来是参数个数不匹配看到这里你可以会说为initialize思路方法提供个重载吧我们试试看:



  图 25

  看起来似乎没问题了如果我再创建个Circle类呢?



  图 26

  又出错了!为什么会这样?原来Ruby不支持思路方法重载我们在图25里创建无参initialize思路方法将会覆盖前面那个带参!显然我们不能通过initialize思路方法来化@sides变量了个可能做法是为@sides变量提供个写访问器:



  图 27

  这下应该没问题了吧?且慢!Person类根本不需要sides思路方法!

  毫无疑问我们陷进共性和个性问题了只有部分类需要sides思路方法而这些类sides思路方法又可能返回区别嗯?这有什么好奇怪我们平时就是这样理解反而特意在这提出来才奇怪呢!是如果你用我们过往经验来理解这里似乎没有什么问题但如果你换个角度就会看到我们现在面临问题了想想看类是什么?Class类例子相同类型部分例子拥有某些思路方法部分没有这意味着什么?噢!反应过来了吗?从另个角度来看对象行为取决于先天和后天两个原因先天是指我们在类(或模块)里创建例子思路方法它们适用于类所有例子那么后天呢?后天是指我们为单个对象创建思路方法它们只适用于单个对象Ruby把这种思路方法叫做单例思路方法(singleton method)

  那么如何创建单例思路方法呢?非常简单就像你创建普通例子思路方法那样区别你要在思路方法名字前面加上对象名字两个名字的间用.分隔为了避免干扰我们再开个新irb:



  图 28

  不会吧?又来种新写法??嘿嘿先别急嘛有没有觉得这个写法似曾相识?细心你可能已经发现它和我们在第篇文章里看到种创建类思路方法写法是除了那个是写在类定义里而这个是写在外面下面我们把那篇文章介绍头两种写法和这里介绍放在起看看:



  代码 3

  当你看到上面这个代码时有没有这样种感觉它们其实是如果有那么恭喜你感觉是对我们知道在Ruby里self指向默认对象而在类定义里默认对象就是类自己所以上面def self.boiling_po和def Mercury.boiling_po那么剩下两种写法呢?我们还是把它们和这里介绍写法放在起看看吧:



  代码 4

  我们知道第 3种写法self其实就是Mercury类换句话说它和第 4种写法区别仅仅在于个在类定义里个在外面但是这只是表面上区别实际上它们是第 4种写法也可以写在类定义里你可以自己试试看那么第 4种写法和第 5种又有什么区别呢?这要从单例思路方法容身的所说起我们知道例子思路方法存在于类或模块里能够它们对象可以在这里找到它们那么单例思路方法呢如果它们只能被单个对象对象又该到哪里才能找到它们?现在细心观察下第 4种写法你觉得它想什么?是不是很像类定义?对了它其实就是个类专门用来存放单例思路方法Ruby把这种类叫做单例类(singleton )每个对象都有两个类个是用来创建例子个则是单例类单例类是自动创建匿名类但你可以通过第 4种写法重新打开它并往里面添加单例思路方法换句话说第 4种写法和第 5种都是用来创建单例思路方法前者直接在对象上创建后者在对象单例类里创建它们的间有个小区别但就目前而言你可以把它们看作

Tags:  ruby正则表达式

延伸阅读

最新评论

发表评论