第三部分 内建类和内建模块

第九章 内建类和内建模块基础知识

一、Ruby 的字面构造器

Ruby 有很多内建类,它们中的大多数可以用 new 来实例化

str = String.new

arr = Array.new

有些则不可以,比如,不可以创建 Integer 类的新实例。


此外,有一部分幸运的内建类还有字面构造器,这意味着可以用特别的记法来创建这些类的对象,而不调用 new。比如:对于 String.new 和 Array.new 来说,更常见到的是 “” 和 []


内建类的字面构造器

字面构造器

示例

String

引号

"new string" 或 'new string'

Symbol

前导冒号

:symbol 或 :"symbol with spaces"

Array

中括号

[1,2,3,4,5]

Hash

大括号

{"New York" => "NY", "Oregon" => "OR"}

Range

二个或三个圆点

0...10 或 0..9

Regexp

斜杠

/([a-z]+)/


二、反复出现的语法糖衣

有操作符风格的语法糖衣调用记法的方法

分类

名称

定义示例

调用示例

糖衣化记法

算术方法/

操作符

+

-

*

/

%

def +(x)

def -(x)

def *(x)

def /(x)

def %(x)

obj.+(x)

obj.-(x)

obj.*(x)

obj./(x)

obj.%(x)

obj + x

obj - x

obj * x

obj / x

obj % x

读/写/添加数据

[]

[]=

<< 

def [](x)

def []=(x,y)

def <<(x)

obj.[](x)

obj.[]=(x,y)

obj.<<(x)

obj[x]

obj[x] = y

obj << x

比较方法/

操作符

==

>

<

>=

<=

def ==(x)

def >(x)

def <(x)

def >=(x)

def <=(x)

obj.==(x)

obj.>(x)

obj.<(x)

obj.>=(x)

obj.<=(x)

obj == x

obj > x

obj < x

obj >= x

obj <= x

case 相等操作符

===

def ===(x)

obj.===(x)

obj === x

这类语法糖衣(看起来像操作符其实是方法调用)的广泛使用,揭示了作为一门编程语言的 Ruby 背后的很多哲学思想。


算术方法/操作符的糖衣记法

糖衣记法

Ruby 如何看待

x += 1

x -= 1

x *= 2

x /= 2

x %= 2

x = x + 1

x = x - 1

x = x * 2

x = x / 2

x = x % 2


三、改变或者不改变其接收者的方法

1. 改变接收者的方法的基本知识

(1)不改变接收者的示例,该例中 str 没有改变 capitalize 方法只返回了一个新的字符串

str = "hello"

puts str.capitalize #输出:Hello

puts str   # 输出:hello


(2)改变接收者的示例,原 str 字符串发生了变化

str = "hello"

str.replace("goodbye")

puts str # 输出:goodbye


(3)改变对象而不是创建新对象的一个考虑是效率:创建新对象,就内存和处理器的资源来说开销很大。


2. 感叹号 ! 方法

Ruby 允许定义方法名以感叹号结尾的方法。


感叹号在 Ruby 内部没有什么特别的意义,不过根据惯例,感叹号表明一个方法是危险的

危险的意味着该方法(与和它同名的没有感叹号的方法不同)永久性地改变它的接收者。


这样的方法对包括:用于数组的 sort/sort!,用于字符串的 upcase/upcase! 和 chomp/chomp!,以及用于字符串和数组的 reverse/reverse!。


3. ActiveRecord 对象扩展了改变接收者的行为

composer = Composer.new
composer.first_name = "Johann"
composer.save
composer.update_attribute("last_name","Bach")

第一个改变将新的作曲者的名字设成 Johann,需要一个手动保存的操作才能将新的值保存到数据库中。第二个改变执行了一个 update_attribute 操作,不仅改变了内存中的对象属性,也更新了数据库中的记录,这种改变叫做横向(lateral)改变或元改变(meta-change)。


四、内建和定制的 to_*(转换)方法

1. Ruby 提供了很多内建方法,这些方法可以将一个类的对象转换为另一类的对象,它们的名字以 to_ 开头:to_s(转换成字符串),to_a(转换成数组),to_i(转换成整数)和 to_f(转换成浮点数)


2. to_s 方法

>> "I am already a string!".to_s

=> "I am already a string!"

还可以返回扁平化的字符串

>> ["one", "two", "three", 4, 5, 6].to_s

=> "onetwothree456"

也可以返回关于某个对象的描述性的字符串

>> Object.new.to_s

=> "#<Object:0x401f81a4>"


3. 编写自己的 to_* 方法

class C


  



  


end


c = C.new("Emma")

puts c


五 、再论迭代器

1. each 的返回值是它的接收者,即最初的数组

array = [1,2,3,4,5]

other = array.each {|n| puts "Current element is #{n}" }

这里,other 只是 array 的另一个引用。保存 each 的返回值没有什么意义。


2. map 的返回值是一个新的数组,这个数组由所有匿名调用的操作结果构成

array = [1,2,3,4,5]

other = array.map {|n| n * 10 }

p other

这个新数组就是 map 调用的返回值:[10,20,30,40,50]


六、布尔状态、布尔对象和空对象

表达式

表达式求值结果对象

表达式的布尔值

1

1+1

true

false

"string"

puts "string"

100 > 50

x = 10

def x; end

1

2

true

false

"string"

nil

true

10

nil

true

true

true

false

true

false

true

true

false


特殊对象 nil

nil 通过 to_s 转换为一个空字符串””;nil的整数表示为0;nil的对象id是4

说 nil 为空是不准确的。可以将 nil 想像成一个存在的对象,它具有一组幸存下来的方法


七、比较两个对象

1. 相等性测试

>> a = Object.new

=> #<Object:0x401c653c>

>> b = Object.new

=> #<Object:0x401c4bd8>

>> a == a

=> true

>> a == b

=> false

>> a.eql?(a)

=> true

>> a.eql?(b)

=> false

>> a.equal?(a)

=> true

>> a.equal?(b)

=> false


2. 比较和 Comparable 模块

(1)混含一个名为 Comparable 的模块(Ruby 提供)

(2)在类中定义一个名为 <=> 的比较方法

比较方法 <=> (太空船操作符或太空船方法),该方法中定义了小于、等于和大于的含义


八、列出对象的方法

1. 列出对象的方法,在 irb 中输入

"I am a String object".methods

对它们进行一下排序

"I am a String object".methods.sort


2. 列出类的方法,而不是实例方法

String.methods.sort

列出 String 类的实例拥有的方法

String.instance_methods


3. 列出对象的单例方法

str = "a plain old string"

"a plain old string"

def str.some_new_method; end

p str.singleton_methods.sort


4. 产生过滤的和有选择的方法列表

如果想了解一个类的实例方法但不包括这个类的祖先类的实例方法,可以传入一个参数

String.instance_methods(false).sort

其它用于列举方法的方法包括以下几个

■ obj.private_methods

■ obj.public_methods

■ obj.protected_methods

■ obj.singleton_methods