<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ftandy (FTAndy)</title>
    <link>https://ruby-china.org/ftandy</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>总结一下 Ruby 中的对象和类模型</title>
      <description>&lt;p&gt;用 Ruby 也快有一年了，总结一下 Ruby 中对象和类模型，表达不是很熟练，请轻喷。&lt;/p&gt;
&lt;h3 id="ruby的对象和类模型到底是什么鬼？"&gt;ruby 的对象和类模型到底是什么鬼？&lt;/h3&gt;
&lt;p&gt;在 ruby 的世界中，有这么三个原则：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;所有东西都是对象，除了 method 和 block（经过&lt;a href="/chiangdi" class="user-mention" title="@chiangdi"&gt;&lt;i&gt;@&lt;/i&gt;chiangdi&lt;/a&gt;提醒，并不是 Ruby 中的任何概念都是对象呢，method 和 block 就不是。 ）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;所有对象都有一个类&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;类最终都继承自源类 Object，而 Object 继承自 BasicObject  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在这个描述中，假设定义了一个类 Dog，实例化一个对象 tidy，对象 tidy 的类是 Dog，Dog 类的类是 Class，
Class 继承自 Module，Module 继承自 Object，Object 最终继承自源类 BasicObject，BasicObject 也是对象，那 BasicObject 的继承自谁？  &lt;/p&gt;

&lt;p&gt;在这里我打开 irb，ruby 的版本为 2.1.2，进行操作。  &lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;tidy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;tidy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; Dog&lt;/span&gt;
&lt;span class="no"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; Class&lt;/span&gt;
&lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superclass&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; Module&lt;/span&gt;
&lt;span class="no"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superclass&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; Object&lt;/span&gt;
&lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superclass&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; BasicObject&lt;/span&gt;
&lt;span class="no"&gt;BasicObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superclass&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;很明显，BasicObject 没有超类，这条贪食蛇吃到这里就终止了。
而 Dog 继承关系上的类概念：Dog，Class，Module，Object，BasicObject 的类都是 Class。  &lt;/p&gt;

&lt;p&gt;也就是说我可以创建这些类概念的实例对象，Dog 就是一只狗，Class 就是一个类，Module 就是一个模块，
Object 就是一个对象，BasicObject 就是一个基础对象。而 Dog，Module 和 Class 自己本身都是 Class 类的一个
实例对象，可以去创建我们想要用的概念对象。  &lt;/p&gt;

&lt;p&gt;而 Object 和 BasicObject 包括一些对象的基本方法，例如 Object 的 nil？方法，
因为所有对象都会继承自 Object，所以所有对象都会有&lt;code&gt;nil&lt;/code&gt;方法；又例如 BasicObject 的&lt;code&gt;instance_eval&lt;/code&gt;方法，因为所有对象
也会继承自 BasicObject，所以所有对象也会有&lt;code&gt;instance_eval&lt;/code&gt;方法。
这些方法都可以在&lt;a href="http://ruby-doc.org/core-2.2.2/BasicObject.html" rel="nofollow" target="_blank" title=""&gt;ruby 的手册&lt;/a&gt;上看到。 &lt;/p&gt;

&lt;p&gt;这里我画了一个继承的图出来。 
&lt;img src="https://l.ruby-china.com/photo/2015/c11cbf514d990362ca34f9c71e58c2d7.png" title="" alt=""&gt;   &lt;/p&gt;

&lt;p&gt;那 BasicObject 和 Object 有没有&lt;code&gt;nil?&lt;/code&gt;和&lt;code&gt;instance_eval&lt;/code&gt;方法呢？
当然会有，因为他是 Class 的实例对象，对象都继承 Object 和 BasicObject，
他们都可以享有自己的方法。  &lt;/p&gt;

&lt;p&gt;而我们在讨论对象和类模型的时候一般都会忽略掉 BasicObject，因为他置于最顶层，我们不会轻易改变他们，
而只讨论 Object 以下的对象和类。  &lt;/p&gt;
&lt;h3 id="eigenclass"&gt;eigenclass&lt;/h3&gt;
&lt;p&gt;eigenclass 也叫元类或者单件类。eigen 的意思为本质的，换我们中国人古代的概念应该叫元神。&lt;br&gt;
每个对象都有自己的 eigenclass，可以通过连个方法找到他。下面代码找出了一只泰迪狗和 Dog 类的元类。  &lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;Dog&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;tidy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;tidy_eigenclass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;tidy&lt;/span&gt;
   &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; 
&lt;span class="n"&gt;tidy_eigenclass&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Class:#&amp;lt;Dog:0x000000023bc5e8&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;tidy_eigenclass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; Class&lt;/span&gt;
&lt;span class="n"&gt;tidy_eigenclass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superclass&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; Dog&lt;/span&gt;

&lt;span class="no"&gt;Dog_eigenclass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dog&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;Dog_eigenclass&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Class:Dog&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dog_eigenclass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;
&lt;span class="no"&gt;Dog_eigenclass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;superclass&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Class:Object&amp;gt;&lt;/span&gt;
&lt;span class="no"&gt;Dog_eigenclass&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的代码的意思是：在泰迪狗和 Dog 类的之前还有一个 eigenclass，Dog 类与 Class 类之前还有一个 eigenclass。
经&lt;a href="/lolychee" class="user-mention" title="@lolychee"&gt;&lt;i&gt;@&lt;/i&gt;lolychee&lt;/a&gt;同学提醒，其实可以通过&lt;code&gt;class &amp;lt;&amp;lt; XXX&lt;/code&gt;和&lt;code&gt;XXX.singleton_class&lt;/code&gt;两种方法来找到对象的元类：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Dog_eigenclass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dog&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;Dog_eigenclass&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Class:Dog&amp;gt;&lt;/span&gt;
&lt;span class="no"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;singleton_class&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Class:Dog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那元类有什么作用呢？&lt;br&gt;
其实有了元类，当我们想要扩展对象和类自身的方法而非继承方法的时候，就变得非常容易，而且可以使用很多种方法来实现。   &lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;
    &lt;span class="s2"&gt;"wowowo"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;
      &lt;span class="s2"&gt;"wowowo"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;
  &lt;span class="s2"&gt;"wowowo"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dog&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;
    &lt;span class="s2"&gt;"wowowo"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的定义代码使得 Dog 类都可以用&lt;code&gt;Dog.bar&lt;/code&gt;来输出"wowowo"。&lt;br&gt;
对类来说，可以使用&lt;code&gt;class_eval&lt;/code&gt;来打开自己来操作类自己。
对对象和类来说，可以使用&lt;code&gt;instance_eval&lt;/code&gt;来打开自己的 eigenclass 来操作自己。&lt;br&gt;
其实自己再画一个继承图就很好理解了。&lt;br&gt;
&lt;img src="https://l.ruby-china.com/photo/2015/812ac64bfcaa3869dd842d8e929f66f9.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;其实还有一个 nil 我还没有画，而 nil 的 class 是 NilClass。当定义一个 Dog，和实例一个对象 tidy 就成这样的图了。
这个只是局部的显示出 eigenclass 视图。有人做出了一个不包含 eigenclass 的 ruby 常用类的关系图，真心跪了。
&lt;img src="https://l.ruby-china.com/photo/2015/39957ccd0f08204244a385a4134ff87c.jpg" title="" alt=""&gt;  &lt;/p&gt;
&lt;h3 id="总结"&gt;总结&lt;/h3&gt;
&lt;p&gt;想要精通 ruby，完全熟悉 ruby 的对象和类模型是不可缺失的一步。&lt;/p&gt;
&lt;h3 id="参考"&gt;参考&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://skilldrick.co.uk/2011/08/understanding-the-ruby-object-model/" rel="nofollow" target="_blank" title=""&gt;Understanding the Ruby object model&lt;/a&gt;    &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://skilldrick.co.uk/2010/11/why-classes-are-confusing-in-ruby/" rel="nofollow" target="_blank" title=""&gt;Why classes are confusing in Ruby&lt;/a&gt;    &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://skilldrick.co.uk/2010/11/something-confusing-about-ruby-object-and-class/" rel="nofollow" target="_blank" title=""&gt;Something confusing about Ruby: Object and Class&lt;/a&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html" rel="nofollow" target="_blank" title=""&gt;Ruby's Eigenclasses Demystified&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://book.douban.com/subject/7056800/" rel="nofollow" target="_blank" title=""&gt;Ruby 元编程&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/7682092/ruby-object-model-class-modules-diagram-anywhere" rel="nofollow" target="_blank" title=""&gt;stackoverflow&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>ftandy</author>
      <pubDate>Sun, 26 Apr 2015 21:44:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/25325</link>
      <guid>https://ruby-china.org/topics/25325</guid>
    </item>
  </channel>
</rss>
