Ruby和元编程之万物皆为对象_ruby专题

开篇

空即是色,色即是空。
空空色色,色色空空,在Ruby语言中,万物皆为对象。

Ruby是一个面向对象的语言(Object Oriented Language),面向对象的概念比其他语言要贯彻的坚定很多。

Ruby中不存在Java中原始类型数据和对象类型数据之分。大部分Ruby中的的东东都是对象。

所以,想要掌握Ruby和Ruby的元编程,对象就是第一门必修功课。本回就着重研究一下Ruby中的对象.

Ruby中的对象

如果你从其他面向对象的语言转来,一提到得到一个对象你可能会想到建立一个类,然后建立这个类的实例出来产生一个对象。

在Ruby中这完全是可以的,不过这种先建立类才能获得对象的过程,听起来更像是面向类的设计,而不是面向对象的设计。关于类的一些东西放到下回再说。

在Ruby中,不存在原始类型的概念,1, 0.3, true/false 甚至 nil都是对象。比如,你可以在irb中尝试下面的代码:

复制代码 代码如下:

>> 1.methods
=> ["%", "odd?", "inspect", "prec_i", "<<", "tap", "div", "&", "clone", ">>", "public_methods", "__send__", "instance_variable_defined?", "equal?", "freeze", "to_sym", "*", "ord", "lcm", "+", "extend", "next", "power!", "send", "round", "methods", <…more methods…> "is_a?", "ceil", "[]"]
>> 1.class
=> Fixnum

你可以在irb中尝试一下其他数据类型,看看他们的方法和类等等信息。

不只是各种数据类型,方法在Ruby中也是对象, 比如下列例子:

复制代码 代码如下:

>> one_plus = 1.method(:+)
=> #<Method: Fixnum#+>
>> one_plus.class
=> Method
>> one_plus.call(2)
=> 3

有意思的是,方法对象也是有方法的:

复制代码 代码如下:

>> one_plus.arity()
=> 1

对象到底是什么?

到底什么是对象呢?

简单的说,**对象就是 状态 + 行为**

状态 就是表明当前对象所拥有的属性,每个同类的对象可能有不同的状态,这些状态保存在实例变量里面(Instance Variable).

对象的实例变量可以由instance_variable_set/instance_variable_get来设定/读取:

复制代码 代码如下:

>> 1.instance_variable_set(:@my_var, "world")
=> "world"
>> 1.instance_variable_get(:@my_var)
=> "world"

行为 行为就是作用在对象上的动作,就是我们常说的方法。Ruby方法的调用,类似于smalltalk或者Objectiv-C,采用消息模式。调用方法相当于对这个对象发送了一个消息。所以对方法的调用也可以这样:

在Ruby中,状态,也就是实例变量是保存在对象里的,而行为或方法则是存在于对象的类或者mixin的module里面。

在静态语言中,编译时就会确定所调用的方法是否存在,不存在会产生编译错误。

Ruby中,当我们在方法调用的运行时,对象会查找他隶属的类,module,父类等,来找到相对应的方法。

Singleton/Meta/Anonymous/Ghost/Shadow Class

1.Singleton Class: 单例类
2.Meta Class:元类
3.Anonymous Class: 匿名类
4.Ghost Class:鬼类
5.Shadow Class: 影子类

上面的这些东东其实说的都是一个东西,我喜欢叫它 影子类。

Ruby中每一个对象都一个一个影子类,这个影子类存在于对象跟它所属的类之间:

对象("obj1") -> 影子类 -> 对象所属的类(String)

当一个对象的方法被调用时,首先查找的是影子类,之后才是它所属的类。

上面讲到实例变量存在于对象内,方法存在于对象的类中。
影子类上的方法,就是只有这一个对象拥有的方法。这个方法通常叫做单例方法(Singleton Method)。

这样的方法只存在于这个对象上,同一个类的其他对象没有这个方法,因为他们的影子类不同,其他对象的影子类上没有这个方法。

复制代码 代码如下:

>> a = "obj1"
=> "obj1"
>> def a.hello
>> puts "hello world"
>> end
=> nil
>> a.hello
hello world
=> nil
>> b = "obj2"
=> "obj2"
>> b.hello
NoMethodError: undefined method `hello' for "obj2":String
    from (irb):49
>> a.singleton_methods
=> ["hello"]
>> b.singleton_methods
=> []

Self

Ruby里面一切都是对象,self也是对象,确切地说是当前对象的引用。

前文说Ruby的方法调用是消息模式,比如obj.method, 消息的接受者是.之前的对象,.之后的是方法及参数。
如果对象和.没有出现的话,消息会被默认送到self对象。除了作为方法的默认接受者,self也是实例变量的解析对象。

self在ruby一开始的时候,被设定为一个叫做main的对象,再irb里面可以看到:

复制代码 代码如下:

>> m = self
=> main

self可以被认为是一个特殊的变量,它的特殊性在于,你不能给他赋值:

复制代码 代码如下:

>> self = "obj"
SyntaxError: compile error
(irb):77: Can't change the value of self
self = "obj"
      ^

有几个办法可以改变self的值,.(obj.method的.)是其中一个,除了.还有class/module关键字。
本回主要关注跟对象相关的.

当我们用obj.method调用方法时,接下来的时间代码的执行就会到相应的方法里,运行的上下文切换到那个对象,self自然也变成了那个对象。用def定义单例方法时,道理也是相通的。 下面的例子可以说明这个self切换的情况。

复制代码 代码如下:

>> a = "obj"
=> "obj"
>> def a.hello_self
>> puts "hello #{self}"
>> end
>> m = self
=> main
>> a.hello_self
hello obj

对象的复制

前文说对象的存在包括两部分,一是状态/实例变量,另一个是行为,本回专注讲了单例方法和影子类。
Ruby中对象的复制也有两种模式,一个是只复制当前的状态/实例变量 dup。另外一种是连同影子类和引用的对象一起复制,从而把单例方法也复制一份。

复制代码 代码如下:

>> a = "obj"
>> def a.hello_self
>> puts "hello #{self}"
>> end
>> b = a.dup
=> "obj"
>> b.hello_self
NoMethodError: undefined method `hello_self' for "obj":String
    from (irb):90
>> b = a.clone
=> "obj"
>> b.hello_self
hello obj

其实有本回上述的这些功能,即便是没有class,Ruby也可以作为一种Prototype(类似JavaScript)的面向对象语言了。

你可以建立一个对象,生成默认的实例变量,把行为作为单例方法定以在这个对象的影子类上,然后用clone生成千千万万个实例。当然这样比较麻烦,但却是可行的途径之一。

其他Object API

对象还有很多其他的功能,比如可以freeze,另外dup跟clone也有一些其他的引用上面的区别,dup只复制引用,clone会吧引用的对象也复制。

这些都可以在Object类(Ruby所有对象的父类)API上找到,可以查看apidock.com的文档

例如关于dup

.dup() produces a shallow copy of obj—the instance variables of obj are copied, but not the objects they reference. dup copies the tainted state of obj. See also the discussion under Object#clone. In general, clone and dup may have different semantics in descendant classes. While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendant object to create the new instance.

本回完

本回讲了些对象相关的东西,有的很基础,有的是Ruby自身的一些特性。

其中Ruby对象模型中最具特色的两个特性就是影子类/单例方法和self,最好能深入理解这两个概念。

且听下回分解

下回注重一些关于类的故事。

时间: 2024-09-20 22:19:49

Ruby和元编程之万物皆为对象_ruby专题的相关文章

基于Ruby的元编程技术

元编程并不是一个很新的概念,通常元编程被认为是通过程序来生成程序,如果从这种意义上来考虑,那么lex和yacc以及JavaCC应该都可以算是具有了元编程的概念,在Java中,元编程得到了广泛的应用.但在Ruby中,元编程的使用变得相当的简单和容易实现,使用Ruby语言本身来产生Ruby代码,不需要借助外部的工具,著名的RoR框架就是建立在Ruby元编程的基础上的.可能你对元编程还没什么概念,但是Ruby已经内建了元编程这种机制,所以很有可能,你在不知不觉中就已经使用了Ruby元编程技术为你带来的

javascript面向对象编程之一 万物皆对象

javascript几乎成了如今web开发人员必学必会的一门语言,但很多人却只停在了一些表单验证等基础操作层面上,在面向对象语言大行其道的当下,我们需要去学习javascript的面向对象的知识,以便更好的掌握javascript.为深入理解各种脚本框架打好基础. javascript和java.C#等语言一样也具有面向对象的一些特征,但细比较的时候,会发现这些特征并不是真正的面向对象,很多地方都是利用对象本身来模拟面向对象,所以认为javascript不能算是面向对象编程语言,而是基于对象的语

Ruby编程中的命名风格指南_ruby专题

用英语命名标识符.    # bad - identifier using non-ascii characters заплата = 1_000 # bad - identifier is a Bulgarian word, written with Latin letters (instead of Cyrillic) zaplata = 1_000 # good salary = 1_000     使用snake_case的形式给变量和方法命名.     # bad :'some sy

用实际代码演示Ruby的容易被误解的6个特性_ruby专题

简介: 假设您是一名 C++ 开发人员,您需要使用 Ruby 快速执行一些原型设计.当您拿起一本 Ruby 参考书籍(比如 Pickaxe)或浏览 Ruby 网站时,会看到一些熟悉的构造,比如类声明.线程支持和异常处理.正当您认为自己了解 Ruby 的工作原理之时,您意识到了,您 Ruby 代码中的并发机制与 Boost 线程工作原理不一样,catch 和 throw 也与它们看上去的大不相同,而且其他人在其 Ruby 脚本中各处使用了名为 self 的关键词.欢迎来到 Ruby 的世界中! 如

详解Ruby设计模式编程中对单例模式的运用_ruby专题

简介      单例模式是设计模式中最简单的形式之一.这一模式的目的是使得类的一个对象成为系统中的唯一实例.要实现这一点,可以从客户端对其进行实例化开始.因此需要用一种只允许生成对象类的唯一实例的机制,"阻止"所有想要生成对象的访问.使用工厂方法来限制实例化过程.这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义. 要点      显然单例模式的要点有三个:一是某个类只能有一个实例:二是它必须自行创建这个实例:三是它必须自行向整个系统提供这个实例.      

万物皆为对象,类(Class)高手们你们是如何理解!

问题描述 RT, 解决方案 解决方案二:施主有何不解?解决方案三:虽然我们一直是搞对象的,但是我们一直单着..解决方案四:楼上给力!解决方案五:期待高手详细回答-解决方案六:老掉牙的问题...解决方案七:对象不好处解决方案八:所有事物都是对象解决方案九:我还没对象呀呀解决方案十:我们脑中"椅子"是个概念,即是个类(class),我们照着这个概念做(new)出了可以摸得到.可以坐.现实的"椅子",即是实例/对象,而木椅.老板椅,就是这样的各个对象,只是属性不同.解决方

Ruby中的反射(Reflection)应用实例_ruby专题

在Java语言中,提供了发射机制,通过发射机制可以通过字符串构造出这个对象,可以获取对象的所有方法(包括私有方法),可以调用私有方法,可以更改成员变量的值(包括私有的成员变量).Ruby也是面向对象的高级语言,当然也提供了反射机制,今天我们讨论通过类名称构造类对象的功能. 一.通过类名称构造类对象 我们先看普通的构造: 复制代码 代码如下: module ModuleA     #the class name, later we will use it to create the corresp

Windows下Ruby on Rails开发环境安装配置图文教程_ruby专题

本文详细介绍如何在Windows配置Ruby on Rails 开发环境,希望对ROR初学者能有帮助. 一.下载并安装Ruby Windows下安装Ruby最好选择 RubyInstaller(一键安装包). 下载地址: http://rubyforge.org/frs/?group_id=167 . 我们这里下载目前较新的rubyinstaller-1.9.3-p0.exe 一键安装包.这个安装包除了包含ruby本身,还有许多有用的扩展(比如gems)和 帮助文档. 双击安装,安装过程出现如下

在Ruby中创建和使用哈希的教程_ruby专题

哈希(Hash)是类似 "employee" => "salary" 这样的键值对的集合.哈希的索引是通过任何对象类型的任意键来完成的,而不是一个整数索引,其他与数组相似. 通过键或值遍历哈希的顺序看起来是随意的,且通常不是按照插入顺序.如果您尝试通过一个不存在的键访问哈希,则方法会返回 nil. 创建哈希 与数组一样,有各种不同的方式来创建哈希.您可以通过 new 类方法创建一个空的哈希: months = Hash.new 您也可以使用 new 创建带有默