《ruby编程语言》笔记2 对象

时间:2022-02-13 08:52:50

ruby是一门非常纯粹的面向对象的语言:所有值都是对象,而且没有基本类型(primitive type)和对象类型的区别,这一点不同于其他语言。在Ruby中,所有对象都继承一个Object类,而且共享那些定义于此类中的方法。

对象引用object references

当我们在ruby中使用对象时,其实是在操作对象的一个引用,而非对象本身。当我们将一个值赋值给一个变量时,我们并没有将一个对象copy到该变量,而是在此变量中存储了一个指向那个对象的引用。下面代码可以说明这点:

s = "Ruby" # Create a String object. Store a reference to it in s.
t = s # Copy the reference to t. s and t both refer to the same object.
t[-1] = "" # Modify the object through the reference in t.
print s # Access the modified object through s. Prints "Rub".
t = "Java" # t now refers to a different object.
print s,t # Prints "RubJava".

When you pass an object to a method in Ruby, it is an object reference that is passed
to the method. It is not the object itself, and it is not a reference to the reference to the
object. Another way to say this is that method arguments are passed by value rather
than by reference, but that the values passed are object references.
Because object references are passed to methods, methods can use those references to
modify the underlying object. These modifications are then visible when the method
returns.

在ruby中,当把一个对象传递给一个方法时,其实传递的是该对象的引用,被传递的既不是对象本身,也不是一个指向该对象的引用的引用。换言之,方法实参时通过”值“而不是”引用“来传递的,只不过这里被传递的值正好 是对象的引用。(这里十分值得注意)

因为对象引用被传递给方法,所以方法可以利用这些引用来修改底层的对象。

《ruby编程语言》笔记2 对象

Fixnum和symbol实现细节上不是引用,但可以看成”引用“。

《ruby编程语言》笔记2 对象

Object Class and Object Type对象类和对象类型

There are several ways to determine the class of an object in Ruby. The simplest is
simply to ask for it:
o = "test" # This is a value
o.class # Returns an object representing the String class
If you are interested in the class hierarchy of an object, you can ask any class what its
superclass is:
o.class # String: o is a String object
o.class.superclass # Object: superclass of String is Object
o.class.superclass.superclass # nil: Object has no superclass
In Ruby 1.9, Object is no longer the true root of the class hierarchy:

在ruby1.9中,Object不再是所有类的根类了:

# Ruby 1.9 only
Object.superclass # BasicObject: Object has a superclass in 1.9
BasicObject.superclass # nil: BasicObject has no superclass

检查一个对象所属类的直接方法就是通过直接比较:
o.class==String

instance_of?方法同样可以完成同样的事情,但是更优雅:
o.instance_of? String

Usually when we test the class of an object, we would also like to know if the object is
an instance of any subclass of that class. To test this, use the is_a? method, or its
synonym kind_of?:

通常情况下,我们想要知道对象是类的某个子类的实例,使用is_a?或同义方法kind_of?
x = 1 # This is the value we're working with
x.instance_of? Fixnum # true: is an instance of Fixnum
x.instance_of? Numeric # false: instance_of? doesn't check inheritance
x.is_a? Fixnum # true: x is a Fixnum
x.is_a? Integer # true: x is an Integer
x.is_a? Numeric # true: x is a Numeric
x.is_a? Comparable # true: works with mixin modules, too
x.is_a? Object # true for any value of x

Class类定义了===操作符,可以替换is_a?
The Class class defines the === operator in such a way that it can be used in place of
is_a?:
Numeric === x # true: x is_a Numeric

This idiom is unique to Ruby and is probably less readable than using the more
traditional is_a? method.

在使用ruby编程的时候,我们常常不太在意一个对象所属的类是什么,只想知道是否可以在它身上调用某些 方法。让我们来看看<<这个例子。一般表示追加,如果我们正在编写一个产生文本输出的方法,那么也可以在该方法中使用这个操作符,然后在调用这个方法的时候,使用任何实现了<<操作符的参数。我们并不在意所属的类型,只要能够通过它调用<<操作符即可。我们可以使用respond_to?方法来测试这一点:

o.respond_to? :"<<"

这种做法的缺点在于它仅仅检查了一个方法的名称,而没有检查该方法的参数。比如,Fixnum和Bignum将<<实现为左移位操作符,而且希望其参数为一个数字而不是字符串。当我们使用respond_to?方法来测试时,整数对象看起来是”可追加的“,但是当我们试图在一个字符串后面添加一个整数时,就会产生错误。对于这个问题没有普遍试用的解决办法,但是对于本例中的情况,一个权宜之计是采用is_a?方法显式地将Numeric对象排除在外。

o.respond_to? :"<<" and not o.is_a? Numeric

关于类型和类之间的差别的另一个例子是StringIO类(ruby标准库)。StringIO使得我们可以对字符串对象进行读写。就像他们是IO对象一样,stirngIO魔法了IO的API。

关注类型而不是类,形成了Ruby中一种被称为” duck typing“的编程风格

对象的相等性Object equality

ruby拥有多的出奇的方法来比较对象的相等性。了解他们的工作机制是非常重要的。这样才能在适当的时候选择正确的方法。

equal?方法

The equal? method is defined by Object to test whether two values refer to exactly the
same object. For any two distinct objects, this method always returns false:
a = "Ruby" # One reference to one String object
b = c = "Ruby" # Two references to another String object
a.equal?(b) # false: a and b are different objects
b.equal?(c) # true: b and c refer to the same object
By convention, subclasses never override the equal? method.
Another way to determine if two objects are, in fact, the same object is to check their
object_id:
a.object_id == b.object_id # Works like a.equal?(b)

==操作符

在Object类里,他是equal?方法的同义词。用于比较两个对象的引用是否是同样的。大多数类都重定义了这个操作符,使不同的实例之间也可以进行相等性测试

a = "Ruby" # One String object
b = "Ruby" # A different String object with the same content

a.equal?(b) # false: a and b do not refer to the same object
a == b # true: but these two distinct objects have equal values
针对java程序员的说明:

If you are a Java programmer, you are used to using the == operator to test if two objects
are the same object, and you are used to using the equals method to test whether two
distinct objects have the same value. Ruby’s convention is just about the opposite of
Java’s.

Numeric类在它们的==操作符里将进行简单的类型转换,因此(比如)fixnum 1和float 1.0通过==比较的结果是相等的。

irb(main):113:0> 1==1.0
=> true

诸如String和Array等类的==操作符,通常要求他的两个操作符属于同一个类。如果右操作数定义了一个to_str或to_ary转换方法,那么原先的==操作符就会调用右侧操作数定义的操作符==,以此来判定是否相等。

!=(不等于)在ruby中用于测试不等性。当ruby见到!=时,他会简单的使用==操作符并且反转结果。这意味着一个类只需定义==操作符来实现其相等性的含义。ruby会为你免费提供!=。但是ruby1.9中,类也可以显示定义他们自己的操作符。

eql?方法

Object将eql?方法定义成equal?方法的同义词,那些重定义了eql?方法的类通常将其作为一个严格版的==操作符,即不予许进行类型转换,比如:
1==1.0 # true:fixnum and float objects an be ==
1.eql?(1.0) #false: but they are never eql?

===操作符

===通常称为”条件相等性(case equality)"操作符,用于测试一个case语句的目标值是否和某个when从句相匹配。

Object类定义了一个默认的===操作符,他会调用==操作符,因此,对于许多类来说,条件相等性和==相等性是一样的。但是某些关键的类重新定义了===,使其不仅仅是一个成员关系或匹配操作符:
Range类定义了===,用于测试一个值是否位于某个范围内

Regexp定义了===,用于测试一个字符串是否与某个正则匹配

Class类定义了===,用于测试一个对象是否是该类的一个实例

在ruby1.9中,Symbol类定义了===,当其左右2个操作数是同一个符号对象时,或者当其右侧操作数是一个持有和左侧符号对象相同文本的字符串时,该操作符返回true。举例如下:

(1..10) === 5 # true: 5 is in the range 1..10
/\d+/ === "123" # true: the string matches the regular expression
String === "s" # true: "s" is an instance of the class String
:s === "s" # true in Ruby 1.9

像这样显式地使用===操作符并不多见,更为常见的是在一个case语句里隐式地使用它。

对象的顺序object orders

在ruby中,类通过实现<=>操作符定义其顺序性。左边小于右边,返回-1,反之返回1.相等返回0。如果2个操作数之间的比较操作没有意义(如:假设右侧操作数属于另一个类)。那么该操作符返回nil。

1 <=> 5 # -1
5 <=> 5 # 0
9 <=> 5 # 1
"1" <=> 5 # nil: integers and strings are not comparable

只要定义了<=>操作符就可以对值进行比较,但是这并不直观,所以,典型情况下,那些定义了<=>操作符的类还会将Comparable模块作为一个mixin包含进来。

对象的转换 object conversion

许多ruby类定义了一些方法,他们可以返回对象的一种表示形式(representation),而这种形式本身却是另一个类的值。比如用于获取一个对象的Stirng表示形式的to_s方法。也许是最常被实现和最有名的了。

Explicit conversions 显示转换
Classes define explicit conversion methods for use by application code that needs to
convert a value to another representation. The most common methods in this category
are to_s, to_i, to_f, and to_a to convert to String, Integer, Float, and Array,
respectively.
Built-in methods do not typically invoke these methods for you. If you invoke a method
that expects a String and pass an object of some other kind, that method is not expected
to convert the argument with to_s. (Values interpolated into double-quoted strings,
however, are automatically converted with to_s.)

内建的方法通常不会自动调用。如果你调用一个参数为String的方法,却传递一个其他类型的对象给它,该方法是不会主动调用参数的to_s方法来进行转换的。(然后,对于那些内插在双引号里面的字符串的值,ruby会利用to_s来自动转换)

(我能说ruby是强类型的吗?)

3.8.7.2 Implicit conversions 隐式转换
Sometimes a class has strong characteristics of some other class. The Ruby Exception
class represents an error or unexpected condition in a program and encapsulates an
error message. In Ruby 1.8, Exception objects are not merely convertible to strings; they
are string-like objects and can be treated as if they were strings in many contexts.* For
example:
# Ruby 1.8 only (1.9运行不了)
e = Exception.new("not really an exception")
msg = "Error: " + e # String concatenation with an Exception
Because Exception objects are string-like, they can be used with the string concatenation
operator. This does not work with most other Ruby classes. The reason that
Exception objects can behave like String objects is that, in Ruby 1.8, Exception implements
the implicit conversion method to_str, and the + operator defined by String
invokes this method on its righthand operand.
Other implicit conversion methods are to_int for objects that want to be integer-like,
to_ary for objects that want to be array-like, and to_hash for objects that want to be
hash-like. Unfortunately, the circumstances under which these implicit conversion
methods are called are not well documented. Among the built-in classes, these implicit
conversion methods are not commonly implemented, either.

对于在何种情形下这些隐士转换方法会被调用,ruby没有很好的文档化。此外,在内建类里,这些隐士转换方法也没用被普遍地实现。

转换函数

Kernel模块定义了4个转换方法,作为全局转换函数。这些函数--Array、float、Integer即String。具有和他们将要转换的类相同的名字,

Array函数试图调用to_ary方法来将其实参转换为一个数组。如果没有定义to_ary方法,或者该方法返回nil,那么Array函数就会试着调用to_a方法。如果没有定义to_a方法,或者该方法返回nil,那么Array函数就会简单地返回一个新数组,并且将其实参作为该数组的一个元素。

《ruby编程语言》笔记2 对象的更多相关文章

  1. Ruby零碎笔记

    Ruby零碎笔记 飞机上阅读pdf的笔记,因为不联网,内容不多而且比较零散,以tips的形式记录 tips 查看当前作用域的变量 puts local_variables ruby中方法传递参数时,括 ...

  2. Ruby入门笔记

    Ruby入门笔记 一切皆为对象 “Hello”.length 方法 定义:def开头 end结尾 命名一般采用下划线分隔单词

  3. Ruby学习笔记(二)

    1.block 代码块 do...end 或 {} 构成一个代码块,就像常见的 .each后面跟的代码块. my_nums = [1,2,3] my_double_nums = my_nums.col ...

  4. Ruby中如何复制对象 &lpar;deep clone&rpar;&lpar;转载&rpar;

    Ruby中如何复制对象 (deep clone) 用Ruby复制一个对象(object)也许没有你想像的那么容易. 今天我google了半天, 做个总结吧. 先从最简单的开始, b = a 是复制吗? ...

  5. Ruby学习笔记4&colon; 动态web app的建立

    Ruby学习笔记4: 动态web app的建立 We will first build the Categories page. This page contains topics like Art, ...

  6. ruby学习笔记(1)-puts&comma;p&comma;print的区别

    ruby学习笔记-puts,p,print的区别 共同点:都是用来屏幕输出的. 不同点:puts 输出内容后,会自动换行(如果内容参数为空,则仅输出一个换行符号):另外如果内容参数中有转义符,输出时将 ...

  7. atitit&period;编程语言&&num;160&semi;类与对象的&&num;160&semi;扩展机制&period;doc

    atitit.编程语言 类与对象的 扩展机制.doc 1.1. Java 下一代: 没有继承性的扩展1 1.2. 继承1 1.3. 使用cglib动态为Java类添加方法1 1.4. 工具类 1 1. ...

  8. Python学习笔记&lowbar;Python对象

    Python学习笔记_Python对象 Python对象 标准类型 其它内建类型 类型对象和type类型对象 Python的Null对象None 标准类型操作符 对象值的比較 对象身份比較 布尔类型 ...

  9. ruby编程语言-学习笔记4(第4章 表达式和操作符)

    4.6.9 范围  Flip-Flops:  ..和... ..和... 操作符不是基于方法的,无法重定义.(优先级比较低) x+1 .. x*x   #可以认为是x+1 至 x*x 的范围 因为操作 ...

随机推荐

  1. Lab1--关于安装JUnit的简要描述

    安装JUnit的过程描述: 下载两个jar包: hamcrest-all-1.3.jar junit-4.12.jar 注意在导入完成jar包之后不要随意改变jar包的路径. 创建java程序,书写如 ...

  2. RabbitMQ学习总结 第三篇:工作队列Work Queue

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  3. InnoSetup能够实现&OpenCurlyDoubleQuote;安装细节描述”界面吗?

    QUOTE( Example_Test.iss ) // 脚本使用了 增强版脚本编辑器 build 091218:Beta2// 编译器版本为 5.3.6.ee1 [Setup]AppName=My ...

  4. Orchard Module&comma;Theme&comma;Core扩展加载概述

    Orchard 源码探索(Module,Theme,Core扩展加载概述) 参考: http://www.orchardch.com/Blog/20120830071458 1. host.Initi ...

  5. 张高兴的 Windows 10 IoT 开发笔记:BMP180 气压传感器

    注意:海拔高度仅供参考 GitHub : https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/BMP180Demo

  6. phpquerylist 抓取数据详解

    参考文档 https://doc.querylist.cc/site/index/doc

  7. Java内存管理-一文掌握虚拟机创建对象的秘密(九)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! [福利]JVM系列学习资源无套路赠送 回顾一下: 本文是接着上一篇内容:Java内存管 ...

  8. Linux期中架构 全网备份案例

    server端脚本 #!/bin/bash #1 进行数据完整性验证 并生成结果 find /backup -type f -name "finger.txt"| xargs md ...

  9. 【LG4841】城市规划

    [LG4841]城市规划 题面 洛谷 题解 记\(t_i\)表示\(i\)个点的无向图个数,显然\(t_i=2^{C_i^2}\). 设\(f_i\)表示\(i\)个点的无向连通图个数,容斥一下,枚举 ...

  10. zabbix install

    Auth: Jin Date: 20140714 用了5 6年的监控工具 http://zabbix.org/wiki/InstallOnCentOS_RHEL Server Install yum ...