[翻译]Ruby教程5——对象

Ruby中的对象

在这章的教程中我们将简要的介绍下Ruby语言对象的概念。更多的内容将会在面向对象的章节中学习。由于Ruby的许多特性可以会使新手们迷惑,尤其是已经学习过其他编程语言的,因此才编写了这个关于对象的预备章节。


Ruby是一门面向对象的编程语言。这意味着我们可以在Ruby语言中使用对象。对于语言程序员来说Ruby程序就是一些字符流。这些符号就是Ruby的关键字、操作符、变量符号和字面量。从语言的角度来看Ruby程序是由对象组成的。这些对象在Ruby脚本程序执行进程来创建和修改。


有两种类型的对象:内置对象和自定义对象。内置对象是所有程序员都可以使用的预定义对象。它们由Ruby语言的内核或者变量库提示。自定义对象是由应用程序开发者在他们的应用程序域中创建的。


所有的对象都必须在使用之前创建。我们把创建对象叫做对象实例化。对象是由数据和方法组成,数据是对象静态的部分,方法是动态的形式。对象的修改以及与其他对象通信都是通过方法进行的。


#!/usr/bin/ruby
puts “Ruby language”

以上是一个简单的Ruby脚本。如果我们熟悉Pascal或者C之类的程序语言,我们可以看到一个名为puts的关键字或者是一个函数和一个字符串参数“Ruby language”


看起来有点不同,Ruby是一门纯面向对象语言。“Ruby language”确实是一个字符串,常见的一种数据类型。但是它也是一个对象。与所有的对象一样,我们可以调用它们的方法。这与其他的语言有点不同。puts是一个方法。方法是定义在一个对象中的函数。方法是不能独自存在的。实际上puts方法是Kernel模块的一部分。


#!/usr/bin/ruby
Kernel.puts “Ruby language”
Kernel.puts “Ruby language”.size

在以上的脚本中我们写了两行代码。


Kernel.puts “Ruby language”

Kernel是可以省略的,在第一个例子中我们调用puts方法就没有使用Kernel。这样可以少打些字节约时间。实际上它是对于Kernel.puts这个正式调用的简写。正如在C#中的Console.writeln和Java中的System.println。因此方法必须与一个对象相关联,或者如果是类方法就必须与类相关联。


Kernel.puts “Ruby language”.size

在这行代码中我们在终端上打印了“Ruby language”这个字符串的长度。对于有其他编程语言经验的程序员来说可能会困惑。在其他语言中字符串是一个原始数据类型,不能修改,并且没有自己的方法。在Ruby中字符串是一个完整的对象,有自己的方法。size方法其中一个,用于返回这个字符串的长度。


$ ./simple2.rb

Ruby language

13


以上是这个例子的输出。




接下来的例子我们看看整数。与字符串相似一个数字也是一个对象。


#!/usr/bin/ruby
puts 6.object_id
puts 6.even?
puts 6.zero?
puts 6.class

这个例子中我们定义了一个数字6。然后调用了一些这个数字的方法。


puts 6.object_id

这里6是一个对象,object_id是一个方法。这个方法返回了与这个对象相关联的id号。每个对象都拥有一个id号。如果我们要在对象上调用一个方法,就必须在他们之间加点号。


puts 6.even?
puts 6.zero?

这里我们对6这个对象调用了两个方法。如果一个数是偶数,那么even?返回true;如果一个数等于0,那么zero?返回true。注意这两个方法都是以问号能结尾的。在Ruby中约定了如果一个方法返回值是布尔类型,那么方法名以问号结尾。


puts 6.class

class方法告诉我们当前正在处理的这个对象是什么类型的。在这里6是一个Fixnum类型。


$ ./objectnumber.rb

13

true

false

Fixnum


以上是这个例子的输出结果。


创建对象


我们之前提到了在Ruby是对象使用之前必须先创建。对象可以被隐式创建或者显式创建。使用字面量符号创建对象是隐式创建;使用new关键字创建对象是显式创建。自定义对象都是显式创建的。自定义对象必须是从某个特定的类创建的。类是对象的模块,一个类可以创建多个对象。


#!/usr/bin/ruby
class Being
end

puts 67
puts “ZetCode”

s = String.new “ZetCode”
puts s

# n1 = Fixnum.new 67
# puts n1

b = Being.new
puts b

这个例子演示了Ruby中的对象创建。


class Being
end

这里是一个名为Being的对象模块。对象模块使用class关键字创建。自定义对象模块通常放在代码文件的顶部,或者分开放在另外的文件中。


puts 67
puts “ZetCode”

这两行代码我们用到了两个对象。Fixnum类型的67String类型的“ZetCode”67“ZetCode”是使用字面符号创建了。字面符号是一个文本,表示了一个类型的特定值。这两个对象是Ruby解释器幕后创建的。在源代码中Ruby的一些对象是使用他们特定的字面符号创建的。


s = String.new “ZetCode”
puts s

这是正式的方法创建字符串对象。它与之前的隐式创建是等价的。


# n1 = Fixnum.new 67
# puts n1

不是所有的内置对象都可以使用new方法来创建。以上代码就不能编译通过。Fixnum对象只能通过字面符号来创建。


b = Being.new
puts b

这里我们创建了自定义对象的一个实例。puts方法输出了这个对象的简短描述。


$ ./ocreation.rb

67

ZetCode

ZetCode

#<Being:0x9944d9c>


以上是输出结果。




继续介绍一些正式的对象创建。


#!/usr/bin/ruby

s1 = String.new “Ruby”
puts s1.size
puts s1.downcase

a1 = Array.new
a1.push 1, 2, 3
puts a1.include? 3
puts a1.empty?

r1 = Range.new 1, 6
puts r1.class
puts r1.include? 4

在这个例子中,我们创建三个内建对象并且调用了几个它们的方法。


s1 = String.new “Ruby”
puts s1.size
puts s1.downcase

创建一个字符串对象,并且调用了它的两个方法。size方法返回这个字符串的长度。downcase方法将这个字符串转为小写。


a1 = Array.new
a1.push 1, 2, 3
puts a1.include? 3
puts a1.empty?

这里创建了一个数组,并往其中添加了三个数字。然后调用了两个数组的方法。include?方法用于检查一个特定的值(在这个例子中是3)是否在数组内。empty?方法返回一个布尔类型的值表明这个数组是否为空。


r1 = Range.new 1, 6
puts r1.class
puts r1.include? 4

创建了一个Range类型的实例对象。它包含了1到6的数字。class方法返回这个对象的类型名称。在这个例子中include?方法检查数字4是否在这个范围内。


$ ./formal.rb

4

ruby

true

false

Range

true


这个例子的运行输出结果。


对象字面符


前面提到了一些内建对象可以使用对象字面符创建。接下来的例子展示了一些对象字面符。


#!/usr/bin/ruby

4.times { puts “Ruby” }

puts “Ruby”.size
puts “Ruby”.downcase

puts [1, 2, 3].include? 3
puts [1, 2, 3].empty?

puts :name.class
puts :name.frozen?

puts (1..6).class
puts (1..6).include? 4

在这个例子中我们使用字面符创建了FixnumStringsArraysSymbolsRanges对象。


4.times { puts “Ruby” }

我们可以直接对一个整数字面符号调用方法。这行代码将在终端上打印4次”Ruby”字符串。


puts “Ruby”.size
puts “Ruby”.downcase

我们对使用字面符号创建的字符串调用了两个方法。


puts [1, 2, 3].include? 3
puts [1, 2, 3].empty?

这里我们使用字面符号创建了两个数组。然后使用include?方法检查一个特定的数字是否是这个数组里;使用empty?方法检查这个数组是否为空。


puts :name.class
puts :name.frozen?

使用以冒号开头的字面符号创建了符号对象,并且调用的它的两个方法。


puts (1..6).class
puts (1..6).include? 4

使用字面符号创建了两个范围对象,并且调用了他们的两个方法。class方法返回这个类的名称,include?方法检查给定的数字是否是这个范围内。


$ ./literals.rb

Ruby

Ruby

Ruby

Ruby

4

ruby

true

false

Symbol

false

Range

true


以上是例子的输出结果。


对象层级


在许多面向对象语言中对象是层级形式的。Ruby中也有对象层级。与树形层级相似,我们也有父对象和子对象。对象从它的父对象中继承数据和行为。层级的顶级是根对象,称为Object。在Ruby中每个对象都至少有一个父对象。也就是就每个对象都继承至Object对象的基类。


根据Ruby的官方文档,Object是Ruby的类层级的根。它的所有方法在所有的类中都是一样的,除非显示的覆盖了。


#!/usr/bin/ruby

puts 4.is_a? Object
puts “Ruby”.is_a? Object
puts [2, 3].is_a? Object
puts :name.is_a? Object
puts (1..2).is_a? Object

以上例子的代码展示了所有对象都是继承至根对象Object


puts 4.is_a? Object

使用is_a?方法检查一个数字是否为特定的类型,也就是说它是否继承至给定的对象类型。


$ ./mother.rb

true

true

true

true

true


所有方法都返回true,意味着所有的对象都继承至母类。




即使是基本的Ruby对象,它们的继承层级也可能是很复杂的。


#!/usr/bin/ruby

puts 6.class

puts 6.is_a? BasicObject
puts 6.is_a? Object
puts 6.is_a? Numeric
puts 6.is_a? Integer
puts 6.is_a? Fixnum

puts 6.is_a? Bignum
puts 6.is_a? String

这个例子展示了小数字的继承层级。


puts 6.class

我们发现数字6的类型是Fixnum


puts 6.is_a? BasicObject
puts 6.is_a? Object
puts 6.is_a? Numeric
puts 6.is_a? Integer
puts 6.is_a? Fixnum

以上这些代码全都返回true。数字6是Fixnum类型。从Ruby文档中我们发现另外四个对象是Fuxnum对象的父类。


puts 6.is_a? Bignum
puts 6.is_a? String

$ ./inheritance.rb

Fixnum

true

true

true

true

true

false

false


以上是输出结果。




这节的最后再举个例子展示下自定义对象的继承。


#!/usr/bin/ruby

class Being

def to_s
“This is Being”
end

def get_id
9
end
end

class Living < Being

def to_s
“This is Living”
end
end

l = Living.new

puts l
puts l.get_id
puts l.is_a? Being
puts l.is_a? Object
puts l.is_a? BasicObject

在这个例子中我们创建了两个对象。BeingLivingLiving对象继承至Being。第一个是父对象,第二介是子对象。


class Being

def to_s
“This is Being”
end

def get_id
9
end
end

这里定义了一个Ruby的自定义对象。定义内容是classend关键字之间。在定义里我们创建了两个方法。当puts方法接了一个对象作为参数时,会调用它的to_s方法。它通常返回这个对象的字符串描述。


class Living < Being

def to_s
“This is Living”
end
end

定义了一个Living对象,这个对象继承至Being对象。<操作符用于创建继承关系。to_s方法被覆盖了。


l = Living.new

我们创建了一个Living实例对象。自定义对象使用new关键字创建。


puts l

puts方法调用Living对象的to_s方法。只有当Living类没有定义to_s方法时,Being类的to_s方法才会被调用。


puts l.get_id

Living对象没有定义get_id方法。在这种情况下就检查它的父类是否有此方法。在这里Being有这个方法,并且被调用。


puts l.is_a? Being

这行将返回trueLiving对象是Being类型的,因为它继承至Being类。


puts l.is_a? Object
puts l.is_a? BasicObject

我们的Living自定义对象中,没有特别显示的指定与Object或者BasicObject的关系。然而这两行也返回true。这是因为在Ruby中所有对象都是自动设置为这两个对象的后代。这是Ruby解释器在幕后完成的。


$ ./custominher.rb

This is Living

9

true

true

true


以上是输出结果。


Ruby的顶级环境


Ruby中有一个特殊的对象引用到Ruby的顶级环境,这是定义在其他上下文之外的默认执行环境。顶级环境名字是main。它是一个Object类型的实例对象。以下main分配了一个局部空间,所有的局部变量有属于它。


#!/usr/bin/ruby

n1 = 3
n2 = 5

puts local_variables

Kernel.puts self
puts self.class

这是描述Ruby顶级环境的第一个例子。


n1 = 3
n2 = 5

我们定义了两个数字类型的变量,这些变量是顶级环境的局部变量。


puts local_variables

这里我们输出所有的局部变量。local_variablesKernel模块的一个方法,它包含了每个顶级环境的对象。


Kernel.puts self

self是Ruby的伪变量。它返回当前对象的接收者。这行将在终端打印“main”。这是顶级环境的名字。Kernel.puts代码部分的Kernel可以省略。完整的名字表示的puts方法属于Kernel模块。


puts self.class

这行打印了顶级环境的类型。我们得到顶级环境的对象类型。它是Object类型,Ruby类层级的根。


$ ./toplevel.rb

n1

n2

main

Object


这是这个例子的输出结果。n1n2是顶级环境所分配的局部变量。main是Ruby顶级执行环境的名字。最后Object是顶级环境的类型。




我们再展示另一个关于Ruby顶级环境的例子。


#!/usr/bin/ruby

@name = “Jane”
@age = 17

def info
“#{@name} is #{@age} years old”
end

puts self.instance_variables
puts self.private_methods.include? :info

puts info

我们展示的属于顶级环境的实例变量和方法。


@name = “Jane”
@age = 17

我们定义了两个实例变量。在Ruby中实例变量以@符号开头。实例变量属于指定的对象实例。在这里是属于Ruby的顶级环境。


def info
“#{@name} is #{@age} years old”
end

这里定义了一个方法。每个方法都必须属于一个对象。这个方法是属于顶级环境的。所有顶级环境的方法都是私有的。私有方法的访问是受制的。


puts self.instance_variables

instance_variables方法打印self的所有实例变量。


puts self.private_methods.include? :info

所有的顶级环境的方法都自动设为私有。private_methods返回该对象所有的私有方法。由于内容太多,我们就调用include?方法来检查info方法是否是其中一个。注意我们是通过符号名来引用info的。


$ ./toplevel2.rb

@name

@age

true

Jane is 17 years old


以上是例子的输出结果。


这章包含了Ruby对象的基本内容。




原文地址: http://zetcode.com/lang/rubytutorial/objects/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial