# Ruby 中的对象 > 原文: [https://zetcode.com/lang/rubytutorial/objects/](https://zetcode.com/lang/rubytutorial/objects/) 在 Ruby 教程的这一部分中,我们将简要介绍 Ruby 语言中对象的概念。 我们将在 OOP 一章中了解有关对象的更多信息。 我写了有关对象的本章,因为许多 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`模块的一部分。 ```ruby #!/usr/bin/ruby Kernel.puts "Ruby language" Kernel.puts "Ruby language".size ``` 在上面的脚本中,我们有两个代码行。 ```ruby Kernel.puts "Ruby language" ``` 在第一个示例中,我们调用的`puts`方法没有`Kernel`部分,可以将其省略。 这样可以节省时间和一些打字。 实际上,这是`Kernel.puts`正式电话的简写。 在 C# 中,我们有`Console.writeln`在 Java 中`System.println`。 想法是一样的。 方法必须与某个对象关联,或者,如果是类方法,则必须与一个类关联。 ```ruby Kernel.puts "Ruby language".size ``` 在此代码行中,我们将`"Ruby language"`字符串的大小打印到控制台。 这可能会使使用其他语言编写代码的程序员感到困惑。 在其他语言中,字符串是无法修改的原始数据类型,并且缺少其自己的方法。 在 Ruby 中,字符串是完整对象,并且具有自己的方法。 `size`方法就是其中一种。 它以字符为单位返回字符串的大小。 ```ruby $ ./simple2.rb Ruby language 13 ``` 代码示例的输出。 在下面的示例中,我们将看一个整数。 与字符串类似,整数值也是 Ruby 对象。 ```ruby #!/usr/bin/ruby puts 6.object_id puts 6.even? puts 6.zero? puts 6.class ``` 在示例中,我们有一个整数 6。我们在数字上调用了一些方法。 ```ruby puts 6.object_id ``` 6 是一个对象。 `object_id`是一种方法。 该方法返回与该对象关联的 ID。 每个对象都有一个 ID。 如果我们在对象上调用方法,则必须始终在两者之间放置点字符。 ```ruby puts 6.even? puts 6.zero? ``` 在这里,我们在 6 个对象上调用两个方法。 如果数字为偶数,则`even?`返回`true`。 如果数字等于零,则`zero?`方法返回`true`。 请注意,这两种方法都以问号结尾。 这是 Ruby 约定。 返回布尔值的方法以问号结尾。 ```ruby puts 6.class ``` `class`方法告诉我们正在处理哪种对象。 在我们的例子中 6 是`Fixnum` ```ruby $ ./objectnumber.rb 13 true false Fixnum ``` 代码示例输出。 ## Ruby 对象创建 我们已经提到必须先创建 Ruby 对象,然后才能使用它们。 可以隐式或显式创建对象。 隐式对象创建是通过字面值符号创建对象。 显式对象的创建通过使用`new`关键字进行。 始终使用`new`关键字创建自定义对象。 必须从特定的类创建自定义对象。 类是对象的模板。 一个类可以用来创建许多对象。 ```ruby #!/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 中创建对象。 ```ruby class Being end ``` 这是名为`Being`的自定义对象的模板。 使用`class`关键字创建模板。 自定义对象的模板通常放在源文件的顶部或单独的 Ruby 文件中。 ```ruby puts 67 puts "ZetCode" ``` 在这两行中,我们使用两个对象。 `Fixnum`类型的 67 对象和`String`类型的`"ZetCode"`字符串。 67 和`"ZetCode"`是我们所谓的字面值。 字面值是类型的特定值的字面值表示。 这两个对象是由 Ruby 解释器在后台创建的。 Ruby 中的某些对象是通过在源代码中指定其字面值来创建的。 ```ruby s = String.new "ZetCode" puts s ``` 这是创建`String`对象的正式方法。 它等于之前使用字符串字面值的隐式创建。 ```ruby # n1 = Fixnum.new 67 # puts n1 ``` 并非所有内置对象都可以使用`new`方法创建。 此代码无法编译。 到目前为止,`Fixnum`数字只能用字面值表示法创建。 ```ruby b = Being.new puts b ``` 在这里,我们创建了自定义对象的实例。 `puts`方法为我们简要介绍了该对象。 ```ruby $ ./ocreation.rb 67 ZetCode ZetCode # ``` 示例的输出。 我们将继续进行一些正式的对象创建。 ```ruby #!/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 ``` 在示例中,我们创建了三个内置对象并调用了其中的一些方法。 ```ruby s1 = String.new "Ruby" puts s1.size puts s1.downcase ``` 创建一个`String`对象。 我们调用对象的两种方法。 `size`方法返回字符串的大小。 `downcase`方法将字符串的字符小写。 ```ruby a1 = Array.new a1.push 1, 2, 3 puts a1.include? 3 puts a1.empty? ``` 在这里,我们创建一个`Array`对象,并向其添加三个数字。 稍后我们调用两个数组方法。 `include?`方法检查特定值(在我们的例子中为 3)是否是数组的一部分。 `empty?`方法返回一个布尔值,指示该数组是否为空。 ```ruby r1 = Range.new 1, 6 puts r1.class puts r1.include? 4 ``` 创建`Range`类的实例。 它包含从 1 到 6 的数字。`class`方法返回对象的名称。 `include?`方法检查数字 4 是否在范围内。 就我们而言。 ```ruby $ ./formal.rb 4 ruby true false Range true ``` 运行示例将给出此输出。 ## Ruby 对象字面值 正如我们已经提到的,可以使用对象字面值来创建一些内置对象。 以下示例显示了几个对象字面值。 ```ruby #!/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 ``` 在上面的示例中,我们使用字面值符号创建一个`Fixnum`,字符串,数组,符号和范围。 ```ruby 4.times { puts "Ruby" } ``` 我们可以立即在整数字面值上调用方法。 该行向终端打印四次`"Ruby"`字符串。 ```ruby puts "Ruby".size puts "Ruby".downcase ``` 我们在用字符串字面值创建的`String`对象上调用两个方法。 ```ruby puts [1, 2, 3].include? 3 puts [1, 2, 3].empty? ``` 在这里,我们使用数组字面值符号创建两个`Array`对象。 我们使用`include?`方法检查特定的数字是否是数组的一部分。 `empty?`方法检查数组对象是否为空。 ```ruby puts :name.class puts :name.frozen? ``` 调用 Symbol 对象的两种方法。 该符号是用一个以冒号开头的符号字面值创建的。 ```ruby puts (1..6).class puts (1..6).include? 4 ``` 使用范围字面值创建两个`Range`对象。 我们在那些对象上调用两个方法。 `class`方法返回类的名称,`include?`方法检查给定数字是否在范围内。 ```ruby $ ./literals.rb Ruby Ruby Ruby Ruby 4 ruby true false Symbol false Range true ``` 示例输出。 ## Ruby 对象层次结构 在许多面向对象的语言中,对象形成层次结构。 Ruby 也具有对象层次结构。 它是一个树状的层次结构,其中有父对象和子对象。 对象从其父对象继承数据和行为。 在层次结构的顶部,有根对象。 它称为`Object`。 Ruby 中的每个对象都有至少一个父对象。 换句话说,每个对象都继承自基本的`Object`对象。 根据 Ruby 的官方文档,`Object`是 Ruby 类层次结构的根。 除非明确重写,否则它的方法可用于所有类。 ```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`继承 ```ruby puts 4.is_a? Object ``` 我们使用`is_a?`方法检查数字是否为特定类型:换句话说,数字是否继承自给定的对象类型。 ```ruby $ ./mother.rb true true true true true ``` 所有方法均返回`true`,这意味着所有对象均从母对象继承。 即使对于非常基本的 Ruby 对象,继承层次结构也可能非常复杂。 ```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 ``` 在此示例中,我们对较小数值的继承层次结构有所了解。 ```ruby puts 6.class ``` 我们找出数字值为 6 的对象是什么。该行将`Fixnum`打印到控制台。 ```ruby 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 文档中,我们发现其他四个对象是`Fixnum`对象的父对象。 ```ruby puts 6.is_a? Bignum puts 6.is_a? String ``` 以上两个对象不是 6 值的父对象。 ```ruby $ ./inheritance.rb Fixnum true true true true true false false ``` 示例的输出。 我们将以一个示例结束本节,该示例演示自定义用户对象的继承。 ```ruby #!/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 ``` 在示例中,我们创建两个对象`Being`和`Living`。 `Living`对象继承自`Being`。 第一个是父对象,第二个是子对象。 ```ruby class Being def to_s "This is Being" end def get_id 9 end end ``` 这是自定义 Ruby 对象的定义。 定义位于`class`和`end`关键字之间。 在定义内部,我们创建两个方法。 当`puts`方法将对象作为参数时,它将调用其`to_s`方法。 它通常给出对象的字符串表示/描述。 ```ruby class Living < Being def to_s "This is Living" end end ``` 我们创建`Living`对象的定义。 该对象继承自`Being`对象。 `<`运算符用于创建继承关系。 `to_s`方法被覆盖。 ```ruby l = Living.new ``` 从上面的`Living`对象模板,我们创建`Living`对象的实例。 使用`new`关键字创建自定义对象的实例。 ```ruby puts l ``` `puts`方法调用`Living`对象的`to_s`方法。 如果`Living`类中未定义`to_s`方法,则将调用`Being`类中的`to_s`方法。 ```ruby puts l.get_id ``` `Living`对象未定义`get_id`方法。 在这种情况下,将检查父类是否存在这种方法。 在我们的情况下,`Being`方法具有这种方法,因此被称为。 ```ruby puts l.is_a? Being ``` 该行返回`true`。 `Living`是`Being`的一种; 例如它继承自`Being`类。 ```ruby puts l.is_a? Object puts l.is_a? BasicObject ``` 对于我们的`Living`自定义对象,我们没有明确指定与`Object`或`BasicObject`对象的任何关系。 但是这两行返回`true`。 这是因为 Ruby 中的每个对象自动都是这两个对象的后代。 这是由 Ruby 解释器在后台完成的。 ```ruby $ ./custominher.rb This is Living 9 true true true ``` Output of the example. ## Ruby 顶级 Ruby 有一个特定的对象,称为 Ruby 顶级。 这是在任何其他上下文(例如类或模块定义)之外定义的默认执行环境。 顶级名称为`main`。 它是`Object`类型的实例。 有一个与`main`关联的局部空间,所有局部变量都驻留在该空间中。 ```ruby #!/usr/bin/ruby n1 = 3 n2 = 5 puts local_variables Kernel.puts self puts self.class ``` 这是描述 Ruby 顶层的第一个示例。 ```ruby n1 = 3 n2 = 5 ``` 在这里,我们定义了两个数值变量。 这些变量是本地变量。 ```ruby puts local_variables ``` 在这里,我们列出了所有局部变量。 `local_variables`是`Kernel`模块的一种方法,已混入每个`Object`(包括顶层对象)中。 ```ruby Kernel.puts self ``` `self`是 Ruby 伪变量。 它返回当前的对象接收者。 该行将`"main"`打印到控制台。 它是 Ruby 顶层的名称。 `Kernel.puts`代码的`Kernel`部分可以省略。 通过完全指定名称,我们显示`puts`方法属于`Kernel`模块。 ```ruby puts self.class ``` 该行显示顶层的`class`。 我们得到顶层的对象类型。 它是`Object`,它是 Ruby 类层次结构的根。 ```ruby $ ./toplevel.rb n1 n2 main Object ``` 这是示例的输出。 `n1`和`n2`是与顶层关联的局部变量。 主要是为 Ruby 顶级执行环境指定的名称。 最后,`Object`是顶层的类型。 我们将有另一个与 Ruby 顶层相关的示例。 ```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 ``` 我们显示了属于顶级环境的实例变量和方法。 ```ruby @name = "Jane" @age = 17 ``` 我们定义了两个实例变量。 实例变量以 Ruby 中的`@`字符开头。 实例变量属于特定的对象实例。 在这种情况下,它们属于 Ruby 顶级。 ```ruby def info "#{@name} is #{@age} years old" end ``` 这是一个方法定义。 每个方法必须属于某个对象。 此方法属于顶级对象。 所有顶级方法都是私有的。 私有方法的访问受到限制。 ```ruby puts self.instance_variables ``` `instance_variables`方法打印出`self`的所有实例变量,在此上下文中指向 Ruby 顶层。 ```ruby puts self.private_methods.include? :info ``` 所有顶级方法都是自动私有的。 `private_methods`返回对象的所有私有方法。 由于方法很多,我们调用`include?`方法来检查`info`方法是否在其中。 请注意,我们通过符号名称来引用`info`方法。 ```ruby $ ./toplevel2.rb @name @age true Jane is 17 years old ``` 示例输出。 本章介绍了 Ruby 语言中对象的一些基础知识。