第三部分 内建类和内建模块
第九章 内建类和内建模块基础知识
一、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